/********** * Copyright (c) 2003-2005 Greg Parker. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. **********/ #include "includes.h" #include "armstubs.h" #include "peal.h" #include "forms/about.h" #include "formutils.h" #include "data/connectionlist.h" #include "data/prefs.h" #include "rsrc/rsrc.h" #include "ssh/ssh.h" #include "forms/resize.h" #include "forms/DIA.h" #include #include "SonyChars.h" #include "terminalform.h" // DO NOT renumber any of these! They are stored in preferences. typedef enum { topAll = -1, // initial state - everything visible topNone = 0, topABC, top123, topIntl, topEtc } top_pane_t; // DO NOT renumber any of these! They are stored in preferences. typedef enum { bottomAll = -1, // initial state - everything visible bottomMini = 0, bottomFull, bottomCust, bottomNone } bottom_pane_t; // DO NOT renumber any of these! They are stored in preferences. typedef enum { rightNone = -1, // initial state - everything visible rightScroll = 0, rightArrows } right_pane_t; typedef enum { caseUpper, caseLower, caseCaps } case_t; typedef enum { keyboardNone = 0, keyboardMini, keyboardFullNone, keyboardFullABC, keyboardFull123, keyboardFullIntl, keyboardFullEtc } keyboard_t; typedef enum { UP = 0, DOWN, RIGHT, LEFT, INVALID_ESC_CHAR } esc_chars_t; static keyboard_t Keyboard; static int TerminalWindowActive = 0; static int deviceTreo6x0 = 0; extern struct ssh_session_t *ss; extern UInt16 NetLibCount; static Boolean OpenNetLib(void) FORMS_SEGMENT; static Boolean StartConnection(void) FORMS_SEGMENT; static void GetVT100Bounds(RectangleType *bounds) FORMS_SEGMENT; static void SetVT100Bounds(RectangleType bounds) FORMS_SEGMENT; static void ShowTitleBar(void) FORMS_SEGMENT; static void HideTitleBar(void) FORMS_SEGMENT; static void SetTitleBar(int show) FORMS_SEGMENT; static Boolean StatusBarShown(void) FORMS_SEGMENT; static void SetStatusBar(Boolean show) FORMS_SEGMENT; static void SetKeyboardHeight(Coord newHeight) FORMS_SEGMENT; static void SetBigShiftKey(void) FORMS_SEGMENT; static void SetSmallShiftKey(void) FORMS_SEGMENT; static void SetABCCase(case_t newcase) FORMS_SEGMENT; static void ShowBottomModifierKeys(Boolean show) FORMS_SEGMENT; static void ShowBottomABCKeys(Boolean show) FORMS_SEGMENT; static void ShowBottomArrowKeys(Boolean show) FORMS_SEGMENT; static void ShowBottomScrollKeys(Boolean show) FORMS_SEGMENT; static void ConstructNoneKeyboard(void) FORMS_SEGMENT; static void DestructNoneKeyboard(void) FORMS_SEGMENT; static void ConstructMiniKeyboard(void) FORMS_SEGMENT; static void DestructMiniKeyboard(void) FORMS_SEGMENT; static void ConstructFullNoneKeyboard(void) FORMS_SEGMENT; static void DestructFullNoneKeyboard(void) FORMS_SEGMENT; static void ConstructFullABCKeyboard(void) FORMS_SEGMENT; static void DestructFullABCKeyboard(void) FORMS_SEGMENT; static void ConstructFull123Keyboard(void) FORMS_SEGMENT; static void DestructFull123Keyboard(void) FORMS_SEGMENT; static void ConstructFullIntlKeyboard(void) FORMS_SEGMENT; static void DestructFullIntlKeyboard(void) FORMS_SEGMENT; static void ConstructFullEtcKeyboard(void) FORMS_SEGMENT; static void DestructFullEtcKeyboard(void) FORMS_SEGMENT; static void ConstructKeyboard(keyboard_t newKeyboard) FORMS_SEGMENT; static void DestructKeyboard(keyboard_t oldKeyboard) FORMS_SEGMENT; static void SetKeyboard(keyboard_t newKeyboard) FORMS_SEGMENT; static unsigned char control_character(unsigned char c) FORMS_SEGMENT; static Boolean CtrlPressed(void) FORMS_SEGMENT; static Boolean MetaPressed(void) FORMS_SEGMENT; static void CtrlPress(Boolean down, Boolean lockDown) FORMS_SEGMENT; static void MetaPress(Boolean down, Boolean lockDown) FORMS_SEGMENT; static void ShiftPress(Boolean down, Boolean lockDown) FORMS_SEGMENT; static void SendModifiedKey(unsigned char c) FORMS_SEGMENT; static void ClearModifiers(void) FORMS_SEGMENT; /* static void SendUpArrowKey(void) FORMS_SEGMENT; */ /* static void SendDownArrowKey(void) FORMS_SEGMENT; */ /* static void SendRightArrowKey(void) FORMS_SEGMENT; */ /* static void SendLeftArrowKey(void) FORMS_SEGMENT; */ static void SendEscapeChar(esc_chars_t) FORMS_SEGMENT; static void SendFKey(UInt16 id) FORMS_SEGMENT; static void SendScrollpadKey(UInt16 id) FORMS_SEGMENT; static void SendEscapeKey(void) FORMS_SEGMENT; static char Backspace(void) FORMS_SEGMENT; static char Backquote(void) FORMS_SEGMENT; static Boolean HandleCtlSelectEvent(EventPtr e) FORMS_SEGMENT; static void TrackDrag(EventPtr e) FORMS_SEGMENT; static void SetScrollBar(FormPtr frmP, SetScrollBarEventType *se) FORMS_SEGMENT; static void CheckDevice(void) FORMS_SEGMENT; static Boolean VT100EventHandler(struct FormGadgetTypeInCallback *gadget, UInt16 cmd, void *paramP) FORMS_SEGMENT; static Boolean HandleCtlRepeatEvent(EventPtr e) FORMS_SEGMENT; Boolean RefreshNetLib(void); // fixme NOT forms segment (used elsewhere w/o prototype) static Boolean OpenNetLib(void) { Err err; UInt16 badIF = 0; if (NetLibCount == 0) { err = NetLibOpen(AppNetRefnum, &badIF); if (err && err != netErrAlreadyOpen) { NetworkError("Could not open network library.", err); return false; } else if (badIF) { NetworkError("Could not open network interface.", badIF); return false; } else { NetLibCount++; } } return RefreshNetLib(); } Boolean RefreshNetLib(void) { Err err; Boolean allUp; UInt16 badIF = 0; // reconnect if necessary err = NetLibConnectionRefresh(AppNetRefnum, true, &allUp, &badIF); if (err) { NetworkError("Could not open network interface.", err); return false; } else if (!allUp) { NetworkError("Could not open network interface.", badIF); return false; } else { return true; } } static Boolean StartConnection(void) { MemHandle recordH; char *hostname; char *portname; char *username; char *displayname; FieldPtr displayField; int port; int result; RectangleType bounds; ss = NULL; recordH=ConnectionListReadSelectedRecord(&hostname, &portname, &username); if (!recordH) return false; port = StrAToI(portname); if (port == 0) port = 22; displayField = PrvGetObjectByID(TerminalHostFieldID); displayname = MemPtrNew(1+StrLen(username)+StrLen("@")+StrLen(hostname)); if (!displayname) { PrvSetFieldToValue(displayField, hostname); } else { StrCopy(displayname, username); StrCat(displayname, "@"); StrCat(displayname, hostname); PrvSetFieldToValue(displayField, displayname); MemPtrFree(displayname); } // draw now in case of error during connection FrmDrawForm(FrmGetActiveForm()); if (!OpenNetLib()) goto done; PrvGetObjectBoundsByID(TerminalTextGadgetID, &bounds); ss = ssh_create(username, bounds); result = ssh_open(ss, hostname, port); if (result < 0) { ssh_free(ss); ss = NULL; } done: MemHandleUnlock(recordH); return (ss != NULL); } static void GetVT100Bounds(RectangleType *bounds) { PrvGetObjectBoundsByID(TerminalTextGadgetID, bounds); } static void SetVT100Bounds(RectangleType bounds) { PrvSetObjectBoundsByID(TerminalTextGadgetID, &bounds); WinEraseRectangle(&bounds, 0); if (ss) ssh_set_bounds(ss, bounds); } static Coord KeyboardHeight = 0; static Boolean inputShown = true; static Boolean titleShown = true; static int titleShift = 0; // distance vt100 moved when title bar was hidden static void ShowTitleBar(void) { RectangleType bounds; if (titleShown) return; // grow vt100 to top of screen GetVT100Bounds(&bounds); bounds.extent.y -= titleShift; bounds.topLeft.y = titleShift; SetVT100Bounds(bounds); // show hostname field PrvShowObjectByID(TerminalHostFieldID); // hide close box PrvHideObjectByID(TerminalCloseBoxButtonID); // set pref titleShown = 1; PrefsPutInt(prefHideTitleBar, 0); } static void HideTitleBar(void) { RectangleType bounds; if (!titleShown) return; // hide hostname field PrvHideObjectByID(TerminalHostFieldID); // show close box PrvShowObjectByID(TerminalCloseBoxButtonID); // grow vt100 to top of screen GetVT100Bounds(&bounds); titleShift = bounds.topLeft.y; bounds.extent.y += titleShift; bounds.topLeft.y = 0; SetVT100Bounds(bounds); // set pref titleShown = 0; PrefsPutInt(prefHideTitleBar, 1); } static void SetTitleBar(int show) { if (show) ShowTitleBar(); else HideTitleBar(); } static Boolean StatusBarShown(void) { return GetDIAState() != DIA_STATE_NO_STATUS_BAR; } static void SetStatusBar(Boolean show) { if (show && GetDIAState() == DIA_STATE_NO_STATUS_BAR) { SetDIAState(DIA_STATE_MIN); } else if (!show) { SetDIAState(DIA_STATE_NO_STATUS_BAR); } } #define NoKeyboardHeight 0 #define MiniKeyboardHeight 25 #define FullKeyboardHeight (25+48) static void SetKeyboardHeight(Coord newHeight) { RectangleType bounds; if (KeyboardHeight != newHeight) { // Adjust VT100 gadget for new height GetVT100Bounds(&bounds); bounds.extent.y += KeyboardHeight; KeyboardHeight = newHeight; bounds.extent.y -= KeyboardHeight; SetVT100Bounds(bounds); } } // intl and ABC use a wider shift key than etc. static void SetBigShiftKey(void) { RectangleType bounds; PrvGetObjectBoundsByID(TerminalTABCShiftButtonID, &bounds); bounds.extent.x = 29; PrvSetObjectBoundsByID(TerminalTABCShiftButtonID, &bounds); } static void SetSmallShiftKey(void) { RectangleType bounds; PrvGetObjectBoundsByID(TerminalTABCShiftButtonID, &bounds); bounds.extent.x = 21; PrvSetObjectBoundsByID(TerminalTABCShiftButtonID, &bounds); } static void SetABCCase(case_t newcase) { static case_t oldcase = -1; Boolean caps = 0, shift = 0; if (newcase == oldcase) return; oldcase = newcase; if (newcase == caseUpper) shift = 1; else if (newcase == caseCaps) caps = 1; GrfSetState(caps, 0, shift); GsiSetShiftState(caps ? glfCapsLock : 0, shift ? 4 : 0); // value 4 should be gsiShiftUpper but isn't, or something DestructKeyboard(Keyboard); ConstructKeyboard(Keyboard); } static void ShowBottomModifierKeys(Boolean show) { PrvSetObjectVisibilityByID(TerminalCtrlButtonID, show); PrvSetObjectVisibilityByID(TerminalMetaButtonID, show); } static void ShowBottomABCKeys(Boolean show) { PrvSetObjectVisibilityByID(TerminalBFullABCButtonID, show); PrvSetObjectVisibilityByID(TerminalBFull123ButtonID, show); PrvSetObjectVisibilityByID(TerminalBFullIntlButtonID, show); PrvSetObjectVisibilityByID(TerminalBFullEtcButtonID, show); } static void ShowBottomArrowKeys(Boolean show) { PrvSetObjectVisibilityByID(TerminalBFullUpButtonID, show); PrvSetObjectVisibilityByID(TerminalBFullDownButtonID, show); PrvSetObjectVisibilityByID(TerminalBFullLeftButtonID, show); PrvSetObjectVisibilityByID(TerminalBFullRightButtonID, show); } static void ShowBottomScrollKeys(Boolean show) { PrvSetObjectVisibilityByID(TerminalRScrollLineUpButtonID, show); PrvSetObjectVisibilityByID(TerminalRScrollLineDownButtonID, show); PrvSetObjectVisibilityByID(TerminalRScrollPageUpButtonID, show); PrvSetObjectVisibilityByID(TerminalRScrollPageDownButtonID, show); } static void ShowGsi(Boolean show) { UInt16 index; FormPtr frmP; GsiEnable(false); frmP = FrmGetActiveForm(); for (index = 0; index < FrmGetNumberOfObjects(frmP); index++) { FormObjectKind type = FrmGetObjectType(frmP, index); if (type == frmGraffitiStateObj) { Coord x, y; FrmGetObjectPosition(frmP, index, &x, &y); if (!show && x < 10000) x += 10000; else if (show && x >= 10000) x -= 10000; FrmSetObjectPosition(frmP, index, x, y); GsiSetLocation(x, y); if (show) FrmShowObject(frmP, index); else FrmHideObject(frmP, index); } } if (show) GsiEnable(true); } static void ConstructNoneKeyboard(void) { PrefsPutInt(prefTopPane, topNone); PrefsPutInt(prefBottomPane, bottomNone); SetKeyboardHeight(NoKeyboardHeight); // nothing to show // hide Graffiti State Indicator ShowGsi(false); } static void DestructNoneKeyboard(void) { // nothing to hide // show Graffiti State Indicator ShowGsi(true); } static void ConstructMiniKeyboard(void) { int i; int count; PrefsPutInt(prefTopPane, topNone); PrefsPutInt(prefBottomPane, bottomMini); SetKeyboardHeight(MiniKeyboardHeight); // T|C: hardware has no '&' // Treo 600/650: hardware has no '_' but does have '&' if (deviceTreo6x0) { PrvSetControlLabel(TerminalBTCAmpersandButtonID, "_"); } ShowBottomModifierKeys(true); ShowBottomScrollKeys(true); PrvShowObjectByID(TerminalBTCButtonsBitmapID); count = TerminalBTCLastButtonID - TerminalBTCFirstButtonID + 1; for (i = 0; i < count; i++) { PrvShowObjectByID(TerminalBTCFirstButtonID + i); } } static void DestructMiniKeyboard(void) { int i; int count; ShowBottomModifierKeys(false); ShowBottomScrollKeys(false); PrvHideObjectByID(TerminalBTCButtonsBitmapID); count = TerminalBTCLastButtonID - TerminalBTCFirstButtonID + 1; for (i = 0; i < count; i++) { PrvHideObjectByID(TerminalBTCFirstButtonID + i); } } static void ConstructFullNoneKeyboard(void) { PrefsPutInt(prefTopPane, topNone); PrefsPutInt(prefBottomPane, bottomFull); SetKeyboardHeight(MiniKeyboardHeight); ShowBottomModifierKeys(true); ShowBottomABCKeys(true); ShowBottomArrowKeys(true); ShowBottomScrollKeys(true); PrvSetControlValue(TerminalBFullABCButtonID, 0); PrvSetControlValue(TerminalBFull123ButtonID, 0); PrvSetControlValue(TerminalBFullIntlButtonID, 0); PrvSetControlValue(TerminalBFullEtcButtonID, 0); } static void DestructFullNoneKeyboard(void) { ShowBottomModifierKeys(false); ShowBottomABCKeys(false); ShowBottomArrowKeys(false); ShowBottomScrollKeys(false); } static void ConstructFullABCKeyboard(void) { int i; int start, end; Boolean caps, num, autoshift; UInt16 shift; PrefsPutInt(prefTopPane, topABC); PrefsPutInt(prefBottomPane, bottomFull); SetKeyboardHeight(FullKeyboardHeight); ShowBottomModifierKeys(true); ShowBottomABCKeys(true); ShowBottomArrowKeys(true); ShowBottomScrollKeys(true); PrvSetControlValue(TerminalBFullABCButtonID, 1); PrvSetControlValue(TerminalBFull123ButtonID, 0); PrvSetControlValue(TerminalBFullIntlButtonID, 0); PrvSetControlValue(TerminalBFullEtcButtonID, 0); // show bitmap and buttons PrvShowObjectByID(TerminalTABCButtonsBitmapID); // choose caps based on Graffiti shift state GrfGetState(&caps, &num, &shift, &autoshift); if (caps) { start = TerminalTABCFirstCapscaseButtonID; end = TerminalTABCLastCapscaseButtonID; PrvSetControlValue(TerminalTABCCapsButtonID, 1); PrvSetControlValue(TerminalTABCShiftButtonID, 0); } else if (shift) { start = TerminalTABCFirstUppercaseButtonID; end = TerminalTABCLastUppercaseButtonID; PrvSetControlValue(TerminalTABCCapsButtonID, 0); PrvSetControlValue(TerminalTABCShiftButtonID, 1); } else { start = TerminalTABCFirstLowercaseButtonID; end = TerminalTABCLastLowercaseButtonID; PrvSetControlValue(TerminalTABCCapsButtonID, 0); PrvSetControlValue(TerminalTABCShiftButtonID, 0); } for (i = start; i <= end; i++) { PrvShowObjectByID(i); } PrvShowObjectByID(TerminalTABCTabButtonID); PrvShowObjectByID(TerminalTABCSpaceButtonID); PrvShowObjectByID(TerminalTABCBackspaceButtonID); PrvShowObjectByID(TerminalTABCReturnButtonID); PrvShowObjectByID(TerminalTABCCapsButtonID); PrvShowObjectByID(TerminalTABCShiftButtonID); SetBigShiftKey(); } static void DestructFullABCKeyboard(void) { int i; int count; ShowBottomModifierKeys(false); ShowBottomABCKeys(false); ShowBottomArrowKeys(false); ShowBottomScrollKeys(false); // hide bitmap and buttons count = TerminalTABCLastButtonID - TerminalTABCFirstButtonID + 1; for (i = 0; i < count; i++) { PrvHideObjectByID(TerminalTABCFirstButtonID + i); } PrvHideObjectByID(TerminalTABCTabButtonID); PrvHideObjectByID(TerminalTABCSpaceButtonID); PrvHideObjectByID(TerminalTABCBackspaceButtonID); PrvHideObjectByID(TerminalTABCReturnButtonID); PrvHideObjectByID(TerminalTABCCapsButtonID); PrvHideObjectByID(TerminalTABCShiftButtonID); PrvHideObjectByID(TerminalTABCButtonsBitmapID); } static void ConstructFull123Keyboard(void) { int i; int count; PrefsPutInt(prefTopPane, top123); PrefsPutInt(prefBottomPane, bottomFull); SetKeyboardHeight(FullKeyboardHeight); ShowBottomModifierKeys(true); ShowBottomABCKeys(true); ShowBottomArrowKeys(true); ShowBottomScrollKeys(true); PrvSetControlValue(TerminalBFullABCButtonID, 0); PrvSetControlValue(TerminalBFull123ButtonID, 1); PrvSetControlValue(TerminalBFullIntlButtonID, 0); PrvSetControlValue(TerminalBFullEtcButtonID, 0); // show bitmap and buttons PrvShowObjectByID(TerminalT123ButtonsBitmapID); count = TerminalT123LastButtonID - TerminalT123FirstButtonID + 1; for (i = 0; i < count; i++) { PrvShowObjectByID(TerminalT123FirstButtonID + i); } PrvShowObjectByID(TerminalT123TabButtonID); PrvShowObjectByID(TerminalT123SpaceButtonID); PrvShowObjectByID(TerminalT123BackspaceButtonID); PrvShowObjectByID(TerminalT123ReturnButtonID); } static void DestructFull123Keyboard(void) { int i; int count; ShowBottomModifierKeys(false); ShowBottomABCKeys(false); ShowBottomArrowKeys(false); ShowBottomScrollKeys(false); // hide bitmap and buttons count = TerminalT123LastButtonID - TerminalT123FirstButtonID + 1; for (i = 0; i < count; i++) { PrvHideObjectByID(TerminalT123FirstButtonID + i); } PrvHideObjectByID(TerminalT123TabButtonID); PrvHideObjectByID(TerminalT123SpaceButtonID); PrvHideObjectByID(TerminalT123BackspaceButtonID); PrvHideObjectByID(TerminalT123ReturnButtonID); PrvHideObjectByID(TerminalT123ButtonsBitmapID); } static void ConstructFullIntlKeyboard(void) { int i; int start, end; Boolean caps, num, autoshift; UInt16 shift; PrefsPutInt(prefTopPane, topIntl); PrefsPutInt(prefBottomPane, bottomFull); SetKeyboardHeight(FullKeyboardHeight); ShowBottomModifierKeys(true); ShowBottomABCKeys(true); ShowBottomArrowKeys(true); ShowBottomScrollKeys(true); PrvSetControlValue(TerminalBFullABCButtonID, 0); PrvSetControlValue(TerminalBFull123ButtonID, 0); PrvSetControlValue(TerminalBFullIntlButtonID, 1); PrvSetControlValue(TerminalBFullEtcButtonID, 0); // show bitmap and buttons PrvShowObjectByID(TerminalTIntlButtonsBitmapID); // choose caps based on Graffiti shift state GrfGetState(&caps, &num, &shift, &autoshift); if (caps) { start = TerminalTIntlFirstUppercaseButtonID; end = TerminalTIntlLastUppercaseButtonID; PrvSetControlValue(TerminalTIntlCapsButtonID, 1); PrvSetControlValue(TerminalTIntlShiftButtonID, 0); } else if (shift) { start = TerminalTIntlFirstUppercaseButtonID; end = TerminalTIntlLastUppercaseButtonID; PrvSetControlValue(TerminalTIntlCapsButtonID, 0); PrvSetControlValue(TerminalTIntlShiftButtonID, 1); } else { start = TerminalTIntlFirstLowercaseButtonID; end = TerminalTIntlLastLowercaseButtonID; PrvSetControlValue(TerminalTIntlCapsButtonID, 0); PrvSetControlValue(TerminalTIntlShiftButtonID, 0); } for (i = start; i <= end; i++) { PrvShowObjectByID(i); } PrvShowObjectByID(TerminalTIntlTabButtonID); PrvShowObjectByID(TerminalTIntlSpaceButtonID); PrvShowObjectByID(TerminalTIntlBackspaceButtonID); PrvShowObjectByID(TerminalTIntlReturnButtonID); PrvShowObjectByID(TerminalTIntlCapsButtonID); PrvShowObjectByID(TerminalTIntlShiftButtonID); SetBigShiftKey(); } static void DestructFullIntlKeyboard(void) { int i; int count; ShowBottomModifierKeys(false); ShowBottomABCKeys(false); ShowBottomArrowKeys(false); ShowBottomScrollKeys(false); // hide bitmap and buttons count = TerminalTIntlLastButtonID - TerminalTIntlFirstButtonID + 1; for (i = 0; i < count; i++) { PrvHideObjectByID(TerminalTIntlFirstButtonID + i); } PrvHideObjectByID(TerminalTIntlTabButtonID); PrvHideObjectByID(TerminalTIntlSpaceButtonID); PrvHideObjectByID(TerminalTIntlBackspaceButtonID); PrvHideObjectByID(TerminalTIntlReturnButtonID); PrvHideObjectByID(TerminalTIntlCapsButtonID); PrvHideObjectByID(TerminalTIntlShiftButtonID); PrvHideObjectByID(TerminalTIntlButtonsBitmapID); } static void ConstructFullEtcKeyboard(void) { int i; int start, end; int start2, end2; Boolean caps, num, autoshift; UInt16 shift; PrefsPutInt(prefTopPane, topEtc); PrefsPutInt(prefBottomPane, bottomFull); SetKeyboardHeight(FullKeyboardHeight); ShowBottomModifierKeys(true); ShowBottomABCKeys(true); ShowBottomArrowKeys(true); ShowBottomScrollKeys(true); PrvSetControlValue(TerminalBFullABCButtonID, 0); PrvSetControlValue(TerminalBFull123ButtonID, 0); PrvSetControlValue(TerminalBFullIntlButtonID, 0); PrvSetControlValue(TerminalBFullEtcButtonID, 1); // show bitmap and buttons PrvShowObjectByID(TerminalTEtcButtonsBitmapID); // choose caps based on Graffiti shift state GrfGetState(&caps, &num, &shift, &autoshift); if (caps) { // no caps in etc, just shift start = TerminalTEtcFirstUppercaseLatin1ButtonID; end = TerminalTEtcLastUppercaseLatin1ButtonID; start2 = TerminalTEtcFirstUppercaseFKeyButtonID; end2 = TerminalTEtcLastUppercaseFKeyButtonID; PrvSetControlValue(TerminalTABCCapsButtonID, 0); PrvSetControlValue(TerminalTEtcShiftButtonID, 1); } else if (shift) { start = TerminalTEtcFirstUppercaseLatin1ButtonID; end = TerminalTEtcLastUppercaseLatin1ButtonID; start2 = TerminalTEtcFirstUppercaseFKeyButtonID; end2 = TerminalTEtcLastUppercaseFKeyButtonID; PrvSetControlValue(TerminalTABCCapsButtonID, 0); PrvSetControlValue(TerminalTEtcShiftButtonID, 1); } else { start = TerminalTEtcFirstLowercaseLatin1ButtonID; end = TerminalTEtcLastLowercaseLatin1ButtonID; start2 = TerminalTEtcFirstLowercaseFKeyButtonID; end2 = TerminalTEtcLastLowercaseFKeyButtonID; PrvSetControlValue(TerminalTABCCapsButtonID, 0); PrvSetControlValue(TerminalTEtcShiftButtonID, 0); } for (i = start; i <= end; i++) { PrvShowObjectByID(i); } for (i = start2; i <= end2; i++) { PrvShowObjectByID(i); } PrvShowObjectByID(TerminalTEtcInsButtonID); PrvShowObjectByID(TerminalTEtcDelButtonID); PrvShowObjectByID(TerminalTEtcHomeButtonID); PrvShowObjectByID(TerminalTEtcEndButtonID); PrvShowObjectByID(TerminalTEtcPgUpButtonID); PrvShowObjectByID(TerminalTEtcPgDnButtonID); PrvShowObjectByID(TerminalTEtcShiftButtonID); SetSmallShiftKey(); } static void DestructFullEtcKeyboard(void) { int i; int count; ShowBottomModifierKeys(false); ShowBottomABCKeys(false); ShowBottomArrowKeys(false); ShowBottomScrollKeys(false); // hide bitmap and buttons count = TerminalTEtcLastButtonID - TerminalTEtcFirstButtonID + 1; for (i = 0; i < count; i++) { PrvHideObjectByID(TerminalTEtcFirstButtonID + i); } PrvHideObjectByID(TerminalTEtcInsButtonID); PrvHideObjectByID(TerminalTEtcDelButtonID); PrvHideObjectByID(TerminalTEtcHomeButtonID); PrvHideObjectByID(TerminalTEtcEndButtonID); PrvHideObjectByID(TerminalTEtcPgUpButtonID); PrvHideObjectByID(TerminalTEtcPgDnButtonID); PrvHideObjectByID(TerminalTEtcShiftButtonID); PrvHideObjectByID(TerminalTEtcButtonsBitmapID); } static void ConstructKeyboard(keyboard_t newKeyboard) { switch (newKeyboard) { case keyboardNone: ConstructNoneKeyboard(); break; case keyboardMini: ConstructMiniKeyboard(); break; case keyboardFullNone: ConstructFullNoneKeyboard(); break; case keyboardFullABC: ConstructFullABCKeyboard(); break; case keyboardFull123: ConstructFull123Keyboard(); break; case keyboardFullIntl: ConstructFullIntlKeyboard(); break; case keyboardFullEtc: ConstructFullEtcKeyboard(); break; default: ConstructFullNoneKeyboard(); break; } } static void DestructKeyboard(keyboard_t oldKeyboard) { switch (oldKeyboard) { case keyboardNone: DestructNoneKeyboard(); break; case keyboardMini: DestructMiniKeyboard(); break; case keyboardFullNone: DestructFullNoneKeyboard(); break; case keyboardFullABC: DestructFullABCKeyboard(); break; case keyboardFull123: DestructFull123Keyboard(); break; case keyboardFullIntl: DestructFullIntlKeyboard(); break; case keyboardFullEtc: DestructFullEtcKeyboard(); break; default: DestructFullNoneKeyboard(); break; } } static void SetKeyboard(keyboard_t newKeyboard) { if (Keyboard == newKeyboard) return; // nothing to do if (Keyboard != (keyboard_t)-1) DestructKeyboard(Keyboard); Keyboard = newKeyboard; ConstructKeyboard(Keyboard); FrmDrawForm(FrmGetActiveForm()); } static unsigned char altsym_symbol_map[32] = { /* SP */ ' ', /* ! */ '|', /* " */ '~', /* # */ '{', /* $ */ '%', /* % */ '%', /* & */ '&', /* ' */ '`', /* ( */ '[', /* ) */ ']', /* * */ '^', /* + */ '=', /* , */ '<', /* - */ '_', /* . */ '>', /* / */ '\\', /* 0 */ ')', /* 1 */ '!', /* 2 */ '@', /* 3 */ '#', /* 4 */ '$', /* 5 */ '%', /* 6 */ '^', /* 7 */ '&', /* 8 */ '*', /* 9 */ '(', /* : */ ';', /* ; */ ':', /* < */ ',', /* = */ '+', /* > */ '.', /* ? */ '}' }; static unsigned char altsym_treo_map[26] = { /* A */ '&', /* B */ '{', /* C */ '*', /* D */ '$', /* E */ '!', /* F */ '%', /* G */ '^', /* H */ '%', /* I */ '&', /* J */ '|', /* K */ ';', /* L */ '`', /* M */ '<', /* N */ '}', /* O */ '~', /* P */ '%', /* Q */ '\\', /* R */ '@', /* S */ '_', /* T */ '#', /* U */ ']', /* V */ '(', /* W */ '=', /* X */ '&', /* Y */ '[', /* Z */ '^' }; static unsigned char altsym_tungsten_map[26] = { /* A */ ';', /* B */ '|', /* C */ ']', /* D */ '=', /* E */ '#', /* F */ '_', /* G */ '^', /* H */ '-', /* I */ '*', /* J */ '~', /* K */ '`', /* L */ '&', /* M */ '}', /* N */ '<', /* O */ '(', /* P */ ')', /* Q */ '!', /* R */ '$', /* S */ '\\', /* T */ '%', /* U */ '&', /* V */ '{', /* W */ '@', /* X */ '[', /* Y */ '^', /* Z */ '%' }; static unsigned char esc_keys[5] = { 'A', // UP 'B', // DOWN 'C', // RIGHT 'D', // LEFT }; static unsigned char altsym_character(unsigned char c) { if (c == '@') return '&'; if (c == '_') return '-'; if (c >= 0x20 && c < 0x40) return altsym_symbol_map[c - 0x20]; if (deviceTreo6x0) { if (c >= 'A' && c <= 'Z') return altsym_treo_map[c - 'A']; if (c >= 'a' && c <= 'z') return altsym_treo_map[c - 'a']; } else { // for now, use tungsten layout on all but treo // note there is currently no way to get altPressed on the tungsten if (c >= 'A' && c <= 'Z') return altsym_tungsten_map[c - 'A']; if (c >= 'a' && c <= 'z') return altsym_tungsten_map[c - 'a']; } return c; } static unsigned char control_character(unsigned char c) { if (c == ' ' || c == '@') return '\0'; // C-space, C-@ if (c >= 'a' && c <= 'z') return c - 'a' + 1; // C-a .. C-z if (c >= 'A' && c <= 'Z') return c - 'A' + 1; // C-A .. C-Z if (c >= '[' && c <= '_') return c - 'A' + 1; // C-[ .. C-_ if (c >= '{' && c <= '}') return c - 'a' + 1; // C-{ .. C-} (no C-~) return c; } static struct { Boolean pressed; // active - affects characters Boolean locked; // locked - does not reset on keypress int gsiState; // indicator to display - 0=off, 1=down, 2=lock int onPress; // new state if button is pressed int onRelease; // new state if button is released } altStateTable[] = { { 0, 0, 0, 1, 0 }, // state 0 - clear { 1, 1, 1, 7, 3 }, // state 1 - held { 1, 1, 1, 1, 0 }, // state 2 - held+ { 1, 0, 1, 4, 3 }, // state 3 - set { 1, 1, 1, 6, 5 }, // state 4 - held set { 1, 1, 2, 6, 5 }, // state 5 - locked { 1, 1, 1, 0, 0 }, // state 6 - locked held { 1, 1, 2, 0, 0 }, // state 7 - double-press { 0, 0, 0, 1, 8 }, // state 8 - locked, masked by graffiti }; #define NUM_ALTSTATES (sizeof(altStateTable)/sizeof(altStateTable[0])) // ctrl or shift locked down (i.e. don't release after sending a key) static Boolean ctrlLocked = 0; static Boolean shiftLocked = 0; static Boolean altPressed = 0; static Boolean altLocked = 0; static int altState = 0; static Boolean altSavedCapsLock = 0; static Boolean altSavedNumLock = 0; static Boolean jogPressed = 0; static Boolean jogPressedCtrl = 0; static Boolean jogPressedMeta = 0; static Boolean keyPressedDuringJogPress = 0; static Boolean jogMovedDuringJogPress = 0; static Boolean scrollByPage = 0; static Boolean CtrlPressed(void) { return PrvGetControlValue(TerminalCtrlButtonID); } static Boolean MetaPressed(void) { // nothing here yet return 0; } static void CtrlPress(Boolean down, Boolean lockDown) { PrvSetControlValue(TerminalCtrlButtonID, down); if (down) ctrlLocked = lockDown; else ctrlLocked = 0; } static void ShiftPress(Boolean down, Boolean lockDown) { if (PrvObjectVisibleByID(TerminalTABCShiftButtonID)) { PrvSetControlValue(TerminalTABCShiftButtonID, down); SetABCCase(down ? caseUpper : caseLower); } if (down) shiftLocked = lockDown; else shiftLocked = 0; } static void AltSetState(int newstate) { UInt16 tst; Boolean ast; if (newstate < 0 || newstate > NUM_ALTSTATES) return; altPressed = altStateTable[newstate].pressed; altLocked = altStateTable[newstate].locked; if (altStateTable[newstate].gsiState != altStateTable[altState].gsiState) { switch (altStateTable[newstate].gsiState) { case 0: // not active; display GSI GrfSetState(altSavedCapsLock, altSavedNumLock, 0); if (PrvObjectVisibleByID(TerminalCtrlButtonID)) { PrvHideObjectByID(TerminalAltPressedBitmapID); PrvHideObjectByID(TerminalAltLockedBitmapID); } GsiEnable(1); break; case 1: // active GrfGetState(&altSavedCapsLock, &altSavedNumLock, &tst, &ast); GrfSetState(0, 0, 0); GsiEnable(0); if (PrvObjectVisibleByID(TerminalCtrlButtonID)) { PrvHideObjectByID(TerminalAltLockedBitmapID); PrvShowObjectByID(TerminalAltPressedBitmapID); } break; case 2: // locked altSavedCapsLock = altSavedNumLock = 0; GrfSetState(0, 0, 0); GsiEnable(0); if (PrvObjectVisibleByID(TerminalCtrlButtonID)) { PrvHideObjectByID(TerminalAltPressedBitmapID); PrvShowObjectByID(TerminalAltLockedBitmapID); } break; } } altState = newstate; } static void AltPress(Boolean down) { if (down) AltSetState(altStateTable[altState].onPress); else AltSetState(altStateTable[altState].onRelease); } static void MetaPress(Boolean down, Boolean lockDown) { // nothing here yet } static void SendModifiedKey(unsigned char c) { Boolean ctrlPressed = CtrlPressed(); if (ctrlPressed) { c = control_character(c); } ClearModifiers(); if (jogPressed) keyPressedDuringJogPress = true; ssh_key(ss, c); } static void ClearModifiers(void) { if (!ctrlLocked) CtrlPress(0, 0); if (!shiftLocked && !PrvGetControlValue(TerminalTABCCapsButtonID)) { ShiftPress(0, 0); } if (altState == 1) AltSetState(2); else if (!altLocked && altState != 8) AltSetState(0); } /* static void SendUpArrowKey(void) */ /* { */ /* ClearModifiers(); */ /* if (ssh_app_cursor_keys(ss)) */ /* ssh_keys(ss, "\eOA", 3); */ /* else */ /* ssh_keys(ss, "\e[A", 3); */ /* } */ /* static void SendDownArrowKey(void) */ /* { */ /* ClearModifiers(); */ /* if (ssh_app_cursor_keys(ss)) */ /* ssh_keys(ss, "\eOB", 3); */ /* else */ /* ssh_keys(ss, "\e[B", 3); */ /* } */ /* static void SendRightArrowKey(void) */ /* { */ /* ClearModifiers(); */ /* if (ssh_app_cursor_keys(ss)) */ /* ssh_keys(ss, "\eOC", 3); */ /* else */ /* ssh_keys(ss, "\e[C", 3); */ /* } */ /* static void SendLeftArrowKey(void) */ /* { */ /* ClearModifiers(); */ /* if (ssh_app_cursor_keys(ss)) */ /* ssh_keys(ss, "\eOD", 3); */ /* else */ /* ssh_keys(ss, "\e[D", 3); */ /* } */ static void SendEscapeChar(esc_chars_t c) { uint8_t sequence[3]; ClearModifiers(); if (c >= INVALID_ESC_CHAR) return; sequence[0] = '\e'; sequence[1] = ssh_app_cursor_keys(ss) ? 'O' : '['; sequence[2] = esc_keys[c]; ssh_keys(ss, sequence, 3); } static void SendFKey(UInt16 id) { char buf[6]; char i = (char)(id - TerminalTEtcFirstFKeyButtonID + 1); // i is 1..20 // fixme other fkey modes would go here // this implementation is PuTTY's "default" mode // F5 => ESC [ 15 ~ .. F20 => ESC [ 34 ~ // but there are gaps in the middle switch (i) { case 1: i = 11; break; case 2: i = 12; break; case 3: i = 13; break; case 4: i = 14; break; case 5: i = 15; break; case 6: i = 17; break; case 7: i = 18; break; case 8: i = 19; break; case 9: i = 20; break; case 10: i = 21; break; case 11: i = 23; break; case 12: i = 24; break; case 13: i = 25; break; case 14: i = 26; break; case 15: i = 28; break; case 16: i = 29; break; case 17: i = 31; break; case 18: i = 32; break; case 19: i = 33; break; case 20: i = 34; break; } snprintf(buf, sizeof(buf), "\e[%d~", i); ClearModifiers(); ssh_keys(ss, buf, strlen(buf)); } static void SendScrollpadKey(UInt16 id) { char buf[5]; // unaffected by application mode snprintf(buf, sizeof(buf), "\e[%d~", id - TerminalTEtcHomeButtonID + 1); ClearModifiers(); ssh_keys(ss, buf, strlen(buf)); } static void SendEscapeKey(void) { ssh_key(ss, '\e'); } static char Backspace(void) { if (PrefsGetInt(prefBackspace, defaultBackspace) == backspaceBS) { return 8; // ascii BS } else { return 127; // ascii DEL } } static char Backquote(void) { if (PrefsGetInt(prefBackquote, defaultBackquote) == backquoteESC) { return '\e'; // ascii ESC } else { return '`'; } } static Boolean HandleCtlSelectEvent(EventPtr e) { UInt16 id = e->data.ctlSelect.controlID; // Check for self-labeled controls if ((id >= TerminalBTCFirstButtonID && id <= TerminalBTCLastButtonID) || (id >= TerminalTABCFirstButtonID && id <= TerminalTABCLastButtonID) || (id >= TerminalT123FirstButtonID && id <= TerminalT123LastButtonID) || (id >= TerminalTIntlFirstButtonID && id <= TerminalTIntlLastButtonID)|| (id >= TerminalTEtcFirstLatin1ButtonID && id <= TerminalTEtcLastLatin1ButtonID)) { const char *text = CtlGetLabel(e->data.ctlSelect.pControl); if (text && text[0]) SendModifiedKey(text[0]); return false; } // Check for FKeys if ((id >= TerminalTEtcFirstFKeyButtonID && id <= TerminalTEtcLastFKeyButtonID)) { SendFKey(id); return false; } switch (id) { case TerminalCtrlButtonID: // nothing to do return false; case TerminalMetaButtonID: // send esc immediately ClearModifiers(); SendEscapeKey(); return false; case TerminalTEtcInsButtonID: case TerminalTEtcDelButtonID: case TerminalTEtcHomeButtonID: case TerminalTEtcEndButtonID: case TerminalTEtcPgUpButtonID: case TerminalTEtcPgDnButtonID: SendScrollpadKey(id); return false; case TerminalTABCTabButtonID: case TerminalT123TabButtonID: SendModifiedKey('\t'); return false; case TerminalTABCSpaceButtonID: case TerminalT123SpaceButtonID: SendModifiedKey(' '); return false; case TerminalTABCBackspaceButtonID: case TerminalT123BackspaceButtonID: SendModifiedKey(Backspace()); return false; case TerminalTABCReturnButtonID: case TerminalT123ReturnButtonID: SendModifiedKey(13); // CR not LF return false; case TerminalTABCShiftButtonID: if (PrvGetControlValue(TerminalTABCShiftButtonID)) { SetABCCase(caseUpper); } else { SetABCCase(caseLower); } return false; case TerminalTABCCapsButtonID: if (PrvGetControlValue(TerminalTABCCapsButtonID)) { SetABCCase(caseCaps); } else { SetABCCase(caseLower); } return false; case TerminalBFullABCButtonID: if (PrvGetControlValue(TerminalBFullABCButtonID)) { SetKeyboard(keyboardFullABC); } else { SetKeyboard(keyboardFullNone); } return false; case TerminalBFull123ButtonID: if (PrvGetControlValue(TerminalBFull123ButtonID)) { SetKeyboard(keyboardFull123); } else { SetKeyboard(keyboardFullNone); } return false; case TerminalBFullIntlButtonID: if (PrvGetControlValue(TerminalBFullIntlButtonID)) { SetKeyboard(keyboardFullIntl); } else { SetKeyboard(keyboardFullNone); } return false; case TerminalBFullEtcButtonID: if (PrvGetControlValue(TerminalBFullEtcButtonID)) { SetKeyboard(keyboardFullEtc); } else { SetKeyboard(keyboardFullNone); } return false; case TerminalCloseBoxButtonID: SetTitleBar(!titleShown); FrmDrawForm(FrmGetActiveForm()); return false; default: return false; } } static void TrackDrag(EventPtr e) { Boolean moved = 0; Boolean stillDown; Coord x, y; static RectangleType slopRect = {{0, 0}, {0, 0}}; static int clickCount = 0; static UInt32 lastClickTime = 0; UInt32 now; // fixme drag stops all network events x = e->screenX; y = e->screenY; // See whether this click counts as a multi-click now = TimGetTicks(); if (RctPtInRectangle(x, y, &slopRect) && now - lastClickTime < SysTicksPerSecond() / 3) { clickCount++; // keep same slop rect } else { clickCount = 1; slopRect.topLeft.x = x - 1; slopRect.topLeft.y = y - 1; slopRect.extent.x = 3; slopRect.extent.y = 3; } lastClickTime = now; // click ssh_click(ss, x, y, clickCount); ssh_click(ss, x, y, -1); while (true) { SysTaskDelay(SysTicksPerSecond() / 30); // don't spin too fast PenGetPoint(&x, &y, &stillDown); if (!stillDown) break; if (!moved) moved = !RctPtInRectangle(x, y, &slopRect); if (moved) { // drag ssh_click(ss, x, y, -1); } } // release ssh_click(ss, x, y, 0); } static void SetScrollBar(FormPtr frmP, SetScrollBarEventType *se) { int total = se->data.sbar.total; int start = se->data.sbar.start; int page = se->data.sbar.page; Boolean newEnabled; Boolean oldEnabled; // enable or disable up arrows newEnabled = (start != 0); oldEnabled = PrvGetControlEnabled(TerminalRScrollLineUpButtonID); if (newEnabled != oldEnabled) { PrvSetControlEnabled(TerminalRScrollLineUpButtonID, newEnabled); PrvSetControlEnabled(TerminalRScrollPageUpButtonID, newEnabled); if (newEnabled) { PrvSetControlGraphics(TerminalRScrollLineUpButtonID, TerminalRScrollLineUpBitmapID, NULL); PrvSetControlGraphics(TerminalRScrollPageUpButtonID, TerminalRScrollPageUpBitmapID, NULL); } else { PrvSetControlGraphics(TerminalRScrollLineUpButtonID, TerminalRScrollLineUpDisabledBitmapID, NULL); PrvSetControlGraphics(TerminalRScrollPageUpButtonID, TerminalRScrollPageUpDisabledBitmapID, NULL); } } // enable or disable down arrows newEnabled = (total > start + page); oldEnabled = PrvGetControlEnabled(TerminalRScrollLineDownButtonID); if (newEnabled != oldEnabled) { PrvSetControlEnabled(TerminalRScrollLineDownButtonID, newEnabled); PrvSetControlEnabled(TerminalRScrollPageDownButtonID, newEnabled); if (newEnabled) { PrvSetControlGraphics(TerminalRScrollLineDownButtonID, TerminalRScrollLineDownBitmapID, 0); PrvSetControlGraphics(TerminalRScrollPageDownButtonID, TerminalRScrollPageDownBitmapID, 0); } else { PrvSetControlGraphics(TerminalRScrollLineDownButtonID, TerminalRScrollLineDownDisabledBitmapID, 0); PrvSetControlGraphics(TerminalRScrollPageDownButtonID, TerminalRScrollPageDownDisabledBitmapID, 0); } } } uint32_t CheckDeviceTreo(void) { static void *sym = NULL; if (!sym) sym = PealLookupSymbol(arm_module, __FUNCTION__ "_stub"); if (!sym) fatal("no ARM symbol %s", __FUNCTION__ "_stub"); return (uint32_t) PealCall(arm_module, sym, NULL); } static void CheckDevice(void) { static Boolean deviceChecked = false; if (deviceChecked) return; // Look for Treo 600, 650, 700p (for keyboard tweaks) deviceTreo6x0 = CheckDeviceTreo(); deviceChecked = true; } static Boolean VT100EventHandler(struct FormGadgetTypeInCallback *gadget, UInt16 cmd, void *paramP) { Boolean handled = false; switch (cmd) { case formGadgetDrawCmd: // Sent to active gadgets any time form is // drawn or redrawn. if (ss) { ssh_activate(ss); ssh_update(ss); } gadget->attr.visible = true; handled = true; break; case formGadgetHandleEventCmd: { EventPtr e = (EventPtr)paramP; // Sent when form receives a gadget event. // paramP points to EventType structure. if (e->eType == frmGadgetEnterEvent) { // penDown in gadget's bounds. UInt16 index; FormPtr frmP = FrmGetActiveForm(); if ((index = FrmGetFocus(frmP)) != noFocus) { // selection in vt100 disables selection in real fields // fixme this might fail if there were a focused table FldSetSelection((FieldPtr)FrmGetObjectPtr(frmP, index), 0, 0); FrmSetFocus(frmP, noFocus); } TrackDrag(e); handled = true; } else if (e->eType == frmGadgetMiscEvent) { // This event is sent by your application // when it needs to send info to the gadget } break; } case formGadgetDeleteCmd: // Perform any cleanup prior to deletion. break; case formGadgetEraseCmd: // FrmHideObject takes care of this if you // return false. handled = false; break; default: handled = false; break; } return handled; } static Boolean HandleCtlRepeatEvent(EventPtr e) { switch (e->data.ctlSelect.controlID) { case TerminalRScrollPageUpButtonID: if (ss) ssh_scroll(ss, -(ssh_visible_height(ss)-1)); return false; case TerminalRScrollPageDownButtonID: if (ss) ssh_scroll(ss, ssh_visible_height(ss)-1); return false; case TerminalRScrollLineUpButtonID: if (ss) ssh_scroll(ss, -1); return false; case TerminalRScrollLineDownButtonID: if (ss) ssh_scroll(ss, 1); return false; // fixme these repeating buttons don't work as smoothly as the 5-way case TerminalBFullUpButtonID: // case TerminalRArrowsUpButtonID: //SendUpArrowKey(); SendEscapeChar(UP); return false; case TerminalBFullDownButtonID: // case TerminalRArrowsDownButtonID: //SendDownArrowKey(); SendEscapeChar(DOWN); return false; case TerminalBFullLeftButtonID: // case TerminalRArrowsLeftButtonID: //SendLeftArrowKey(); SendEscapeChar(LEFT); return false; case TerminalBFullRightButtonID: // case TerminalRArrowsRightButtonID: //SendRightArrowKey(); SendEscapeChar(RIGHT); return false; default: return false; } } Boolean TerminalFormHandleEvent(EventPtr e) { FormPtr frmP = FrmGetActiveForm(); if (ResizeHandleEvent(e)) return true; switch (e->eType) { case frmOpenEvent: // reset display states to default Keyboard = -1; // updated by first SetKeyboard() KeyboardHeight = NoKeyboardHeight; inputShown = true; titleShown = true; ctrlLocked = 0; shiftLocked = 0; altPressed = 0; altLocked = 0; altState = 0; altSavedCapsLock = altSavedNumLock = 0; jogPressed = 0; jogPressedCtrl = 0; jogPressedMeta = 0; keyPressedDuringJogPress = 0; jogMovedDuringJogPress = 0; scrollByPage = 0; // check for device-specific hacks and features CheckDevice(); // set up virtual graffiti support and initial keyboard state FrmSetGadgetHandler(FrmGetActiveForm(), PrvGetObjectIndexByID(TerminalTextGadgetID), VT100EventHandler); SetTitleBar(! PrefsGetInt(prefHideTitleBar, 0)); PrvHideObjectByID(TerminalAltPressedBitmapID); PrvHideObjectByID(TerminalAltLockedBitmapID); GsiEnable(1); { int top = PrefsGetInt(prefTopPane, topNone); int bot = PrefsGetInt(prefBottomPane, bottomFull); if (bot != bottomFull) { switch (bot) { case bottomNone: SetKeyboard(keyboardNone); break; case bottomMini: SetKeyboard(keyboardMini); break; default: SetKeyboard(keyboardFullNone); break; } } else { switch (top) { case topNone: SetKeyboard(keyboardFullNone); break; case topABC: SetKeyboard(keyboardFullABC); break; case top123: SetKeyboard(keyboardFull123); break; case topIntl: SetKeyboard(keyboardFullIntl); break; case topEtc: SetKeyboard(keyboardFullEtc); break; } } // SetKeyboard() draws the form. } FrmDrawForm(FrmGetActiveForm()); StartConnection(); return true; case menuEvent: switch (e->data.menu.itemID) { case MenuDisconnect: FrmGotoForm(MainFormID); return true; case MenuAboutPalmSSH: FrmPopupForm(AboutFormID); return true; case MenuCredits: FrmPopupForm(CreditsFormID); return true; case MenuDisplaySettings: FrmPopupForm(DisplayPrefsFormID); return true; case MenuKeyboardSettings: FrmPopupForm(KeyboardPrefsFormID); return true; case MenuCtrl: if (CtrlPressed()) CtrlPress(0, 0); else CtrlPress(1, 0); return true; case MenuEsc: ClearModifiers(); SendEscapeKey(); return true; case sysEditMenuUndoCmd: // no undo in vt100 - send to fields return false; case sysEditMenuCutCmd: // no cut in vt100 - copy will do // FALL-THROUGH to copy case sysEditMenuCopyCmd: if (FrmGetFocus(FrmGetActiveForm()) == noFocus) { ssh_copy(ss); // don't send to other fields return true; } else { return false; } case sysEditMenuPasteCmd: if (FrmGetFocus(FrmGetActiveForm()) == noFocus) { ssh_paste(ss); // don't send to other fields return true; } else { // let real fields handle it return false; } case sysEditMenuKeyboardCmd: if (Keyboard != keyboardFullABC) { SetKeyboard(keyboardFullABC); } else { SetKeyboard(keyboardFullNone); } return true; case sysEditMenuGraffitiCmd: SysGraffitiReferenceDialog(referenceDefault); return true; case MenuTCKeyboard: // "Mini Keyboard" SetKeyboard(keyboardMini); return true; case MenuNoKeyboard: SetKeyboard(keyboardNone); return true; case MenuToggleTitle: SetTitleBar(!titleShown); FrmDrawForm(FrmGetActiveForm()); return true; case MenuToggleStatusBar: SetStatusBar(!StatusBarShown()); return true; default: return false; } case menuCmdBarOpenEvent: { UInt16 len; // fixme buttons get added in wrong order if hostname field has // a selection (need to override default field buttons) // add "paste" button if there is clipboard content if (ClipboardGetItem(clipboardText, &len)) { MenuCmdBarAddButton(menuCmdBarOnLeft, BarPasteBitmap, menuCmdBarResultMenuItem, sysEditMenuPasteCmd, NULL); } // add "copy" button if there is a terminal selection if (ssh_selection_exists(ss)) { MenuCmdBarAddButton(menuCmdBarOnLeft, BarCopyBitmap, menuCmdBarResultMenuItem, sysEditMenuCopyCmd, NULL); } return false; } case frmCloseEvent: if (ss) { ssh_close(ss); ssh_free(ss); ss = NULL; } return false; case fldEnterEvent: // selection in real field disables selection in vt100 if (ss) { ssh_deselect(ss); } return false; case ctlRepeatEvent: return HandleCtlRepeatEvent(e); case ctlSelectEvent: return HandleCtlSelectEvent(e); case keyDownEvent: { WChar chr = e->data.keyDown.chr; if (!EvtKeydownIsVirtual(e)) { unsigned char c = (unsigned char)chr; // send CR rather than LF if (c == 10) c = 13; // remap DEL or BS based on backspace configuration if (c == 8 || c == 127) { if (altPressed) { SendScrollpadKey(TerminalTEtcDelButtonID); //DELETE return true; } c = Backspace(); } if (altPressed) c = altsym_character(c); // remap ` based on backquote configuration if (c == '`') c = Backquote(); // send arrow key control codes rather than ASCII values if (c == 28) SendEscapeChar(LEFT);//SendLeftArrowKey(); else if (c == 29) SendEscapeChar(RIGHT);//SendRightArrowKey(); else if (c == 30) SendEscapeChar(UP);//SendUpArrowKey(); else if (c == 31) SendEscapeChar(DOWN);//SendDownArrowKey(); // handle ctrl modifier on external keyboard else if (e->data.keyDown.modifiers & controlKeyMask) SendModifiedKey(control_character(c)); else SendModifiedKey(c); return true; } // Treo 600/650 5-way hack: translate PageUp/Down into RockerUp/Down if (deviceTreo6x0 && chr == vchrPageUp) { chr = vchrRockerUp; } if (deviceTreo6x0 && chr == vchrPageDown) { chr = vchrRockerDown; } // Handle interesting vchrs if (chr == vchrKeyboard || chr == vchrKeyboardAlpha) { if (Keyboard != keyboardFullABC) { SetKeyboard(keyboardFullABC); } else { SetKeyboard(keyboardFullNone); } return true; } else if (chr == vchrKeyboardNumeric) { if (Keyboard != keyboardFull123) { SetKeyboard(keyboardFull123); } else { SetKeyboard(keyboardFullNone); } return true; } else if (chr == 0x51d) { // Tungsten|C fn-space (usually runs sys keyboard in symbol pane) // Here cycle among full(123) and T|C and none if (Keyboard == keyboardMini) { SetKeyboard(keyboardFull123); } else if (Keyboard == keyboardNone) { SetKeyboard(keyboardMini); } else { SetKeyboard(keyboardNone); } return true; } else if (chr == 0x1609 && !(e->data.keyDown.modifiers & autoRepeatKeyMask)) { AltPress(1); return true; } else if (chr == 0x161b) { // Treo volume up -> scroll up if (ss) { if (scrollByPage) ssh_scroll(ss, -(ssh_visible_height(ss)-1)); else ssh_scroll(ss, -1); } return true; } else if (chr == 0x161c) { // Treo volume down -> scroll down if (ss) { if (scrollByPage) ssh_scroll(ss, (ssh_visible_height(ss)-1)); else ssh_scroll(ss, 1); } return true; } else if (chr == 0x161f) { // Treo side button -> toggle scroll mode scrollByPage = !scrollByPage; return true; } else if (chr == vchrThumbWheelUp || chr == vchrJogUp) { // scroll up (fixme how far?) if (ss) ssh_scroll(ss, -1); return true; } else if (chr == vchrThumbWheelDown || chr == vchrJogDown) { // scroll down (fixme how far?) if (ss) ssh_scroll(ss, +1); return true; } else if (chr == vchrJogPushedUp) { // scroll up if (ss) ssh_scroll(ss, -(ssh_visible_height(ss)-1)); if (CtrlPressed()) CtrlPress(0, 0); // set in JogPush if (MetaPressed()) MetaPress(0, 0); jogMovedDuringJogPress = 1; return true; } else if (chr == vchrJogPushedDown) { // scroll down (fixme how far?) if (ss) ssh_scroll(ss, ssh_visible_height(ss)-1); if (CtrlPressed()) CtrlPress(0, 0); // set in JogPush if (MetaPressed()) MetaPress(0, 0); jogMovedDuringJogPress = 1; return true; } else if (NavSelectPressed(e) || chr == vchrRockerCenter || chr == vchrThumbWheelPush) { // Palm 5-way / thumb wheel push == once for ctrl, twice for esc int ctrlWasPressed = CtrlPressed(); if (ctrlWasPressed) { // clear ctrl and send esc ClearModifiers(); SendEscapeKey(); } else { CtrlPress(1, 0); } return true; } else if (chr == vchrJogPress) { // jog wheel push = ctrl/esc and page scroll jogPressed = 1; keyPressedDuringJogPress = 0; jogMovedDuringJogPress = 0; if (!CtrlPressed()) { CtrlPress(1, 1); // lock until further notice jogPressedCtrl = 1; jogPressedMeta = 0; } else { CtrlPress(0, 0); MetaPress(1, 1); // lock until further notice jogPressedCtrl = 0; jogPressedMeta = 1; } return true; } else if (chr == vchrJogRelease) { if (jogPressedCtrl && CtrlPressed()) { if (jogMovedDuringJogPress || keyPressedDuringJogPress) { // scroll or ctrl-key sent - release ctrl CtrlPress(0, 0); } else { // jog press and release - unlock ctrl but leave it set CtrlPress(1, 0); } } else if (jogPressedMeta /* && MetaPressed() */) { if (jogMovedDuringJogPress || keyPressedDuringJogPress) { // scroll or meta-key sent - release meta MetaPress(0, 0); } else { // jog press and release - release meta and send esc MetaPress(0, 0); SendEscapeKey(); } } return true; } else if (NavDirectionPressed(e, Up) || chr == vchrRockerUp) { ClearModifiers(); // SendUpArrowKey(); SendEscapeChar(UP); return true; } else if (NavDirectionPressed(e, Down) || chr == vchrRockerDown) { ClearModifiers(); // SendDownArrowKey(); SendEscapeChar(DOWN); return true; } else if (NavDirectionPressed(e, Right) || chr == vchrRockerRight) { ClearModifiers(); // SendRightArrowKey(); SendEscapeChar(RIGHT); return true; } else if (NavDirectionPressed(e, Left) || chr == vchrRockerLeft) { ClearModifiers(); // SendLeftArrowKey(); SendEscapeChar(LEFT); return true; } return false; } case keyHoldEvent: if (e->data.keyHold.chr == 0x1609) { // Treo alt key, held down if (altState == 1) AltSetState(2); return true; } return false; case keyUpEvent: if (e->data.keyUp.chr == 0x1609) { // Treo alt key, released AltPress(0); return true; } return false; case winExitEvent: if ((FormPtr)e->data.winExit.exitWindow == FrmGetFormPtr(TerminalFormID)) { TerminalWindowActive = false; if (ss) ssh_deactivate(ss); return true; } return false; case winEnterEvent: if ((FormPtr)e->data.winEnter.enterWindow == FrmGetFormPtr(TerminalFormID)) { if (ss) ssh_activate(ss); TerminalWindowActive = true; return true; } return false; case usrDrawVT100Event: if (ss) ssh_update(ss); return true; case usrDrawCloseBoxEvent: // draw close box if it should be visible // fixme test for status bar too? if (!titleShown) { PrvDrawControl(TerminalCloseBoxButtonID); } return true; case usrSetScrollBarEvent: { SetScrollBarEventType *se = (SetScrollBarEventType *)e; SetScrollBar(frmP, se); return true; } default: return false; } } static Boolean IsStealableVchr(EventPtr e) { if (e->data.keyDown.chr == 0x1609) return true; // treo alt if (e->data.keyDown.chr == 0x161b) return true; // volume up if (e->data.keyDown.chr == 0x161c) return true; // volume down if (e->data.keyDown.chr == vchrKeyboard) return true; if (e->data.keyDown.chr == vchrKeyboardAlpha) return true; if (e->data.keyDown.chr == vchrKeyboardNumeric) return true; if (e->data.keyDown.chr == 0x51d) return true; if (e->data.keyDown.chr == vchrJogPushedDown && TerminalWindowActive) return true; if (e->data.keyDown.chr == vchrJogPushedUp && TerminalWindowActive) return true; if (e->data.keyDown.chr == vchrRockerDown && TerminalWindowActive) return true; if (e->data.keyDown.chr == vchrRockerUp && TerminalWindowActive) return true; if (e->data.keyDown.chr == vchrJogDown && TerminalWindowActive) return true; if (e->data.keyDown.chr == vchrJogUp && TerminalWindowActive) return true; return false; } // Terminal form wants to catch some key events before the system uses them: // - keyboard vchrs to display its own keyboard // - Treo alt key for second symbol shift level // - Sony jog wheel and Treo 5-way vchrs Boolean TerminalFormStealEvent(EventPtr e) { // don't steal if terminal is not active, or if event is not key down if (FrmGetActiveFormID() != TerminalFormID) return false; if (e->eType != keyDownEvent) return false; // Special processing per event type switch (e->eType) { case keyDownEvent: // keycode debugging if (TerminalWindowActive) { FieldPtr displayField; char keytext[40]; Boolean caps, num, autoshift; UInt16 shift; GrfGetState(&caps, &num, &shift, &autoshift); sprintf(keytext, "+c:%04x k:%04x m:%04x %s%s%s%d", e->data.keyDown.chr, e->data.keyDown.keyCode, e->data.keyDown.modifiers, caps ? "C" : "-", num ? "N" : "-", autoshift ? "N" : "-", shift); displayField = PrvGetObjectByID(TerminalHostFieldID); PrvSetFieldToValue(displayField, keytext); FldDrawField(displayField); } // any keyboard modifier press turns off alt if (e->data.keyDown.chr == 0x160d) { if (altState == 5 || altState == 8) AltSetState(8); else AltSetState(0); } // steal some key-down events for the form event handler break; case keyHoldEvent: // keycode debugging if (TerminalWindowActive) { FieldPtr displayField; char keytext[40]; Boolean caps, num, autoshift; UInt16 shift; GrfGetState(&caps, &num, &shift, &autoshift); sprintf(keytext, "*c:%04x k:%04x m:%04x %s%s%s%d", e->data.keyDown.chr, e->data.keyDown.keyCode, e->data.keyDown.modifiers, caps ? "C" : "-", num ? "N" : "-", autoshift ? "N" : "-", shift); displayField = PrvGetObjectByID(TerminalHostFieldID); PrvSetFieldToValue(displayField, keytext); FldDrawField(displayField); } // steal some key-hold events for the form event handler break; case keyUpEvent: // keycode debugging if (TerminalWindowActive) { FieldPtr displayField; char keytext[40]; Boolean caps, num, autoshift; UInt16 shift; GrfGetState(&caps, &num, &shift, &autoshift); sprintf(keytext, "-c:%04x k:%04x m:%04x %s%s%s%d", e->data.keyUp.chr, e->data.keyUp.keyCode, e->data.keyUp.modifiers, caps ? "C" : "-", num ? "N" : "-", autoshift ? "N" : "-", shift); displayField = PrvGetObjectByID(TerminalHostFieldID); PrvSetFieldToValue(displayField, keytext); FldDrawField(displayField); } // steal some key-up events for the form event handler break; default: // don't steal other events return false; } // steal some virtual chars anytime if (EvtKeydownIsVirtual(e) && IsStealableVchr(e)) return true; // don't steal return false; } // Special handling _after_ an event is processed void TerminalFormPostEvent(EventPtr e) { // don't process if terminal is not active if (FrmGetActiveFormID() != TerminalFormID) return; // Special processing per event type switch (e->eType) { case keyUpEvent: // if a keyboard modifier was released, update alt state if (e->data.keyDown.chr == 0x160d) { Boolean caps, num, autoshift; UInt16 shift; GrfGetState(&caps, &num, &shift, &autoshift); if (caps || num) { // any lock state resets saved alt lock AltSetState(0); } else if (altState == 8 && !shift) { // no modifiers still down; restore alt lock state AltSetState(5); } } default: } } // Resize the terminal form void TerminalFormResize(FormPtr frmP, Int16 dh, Int16 dv) { UInt16 index; // fixme only handles vertical well // hostname field: resize to width // close box: move horizontally // vt100 gadget: resize to width and height // everything else: move vertically for (index = 0; index < FrmGetNumberOfObjects(frmP); index++) { UInt16 id = FrmGetObjectId(frmP, index); FormObjectKind type = FrmGetObjectType(frmP, index); if (id == frmInvalidObjectId && type != frmGraffitiStateObj) continue; if (id == TerminalHostFieldID) { // fixme } else if (id == TerminalTextGadgetID) { RectangleType bounds; FrmGetObjectBounds(frmP, index, &bounds); bounds.extent.x += dh; bounds.extent.y += dv; SetVT100Bounds(bounds); } else if (id == TerminalHostFieldID) { RectangleType bounds; FrmGetObjectBounds(frmP, index, &bounds); bounds.extent.x += dh; FrmSetObjectBounds(frmP, index, &bounds); } else if (id == TerminalCloseBoxButtonID) { PrvMoveObject(frmP, id, dh, 0); } else { switch (type) { case frmBitmapObj: PrvMoveObject(frmP, id, 0, dv); break; case frmGraffitiStateObj: { // FrmSetObjectPosition is insufficient for Gsi Coord x, y; GsiEnable(false); FrmGetObjectPosition(frmP, index, &x, &y); y += dv; FrmSetObjectPosition(frmP, index, x, y); GsiSetLocation(x, y); GsiEnable(true); break; } default: PrvMoveObject(frmP, id, 0, dv); break; } } } }