home *** CD-ROM | disk | FTP | other *** search
/ PC Musician 2000 / PC_Musician_2000.iso / PCMUSIC / MISC / MDJSTK10 / JOY_CTRL.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1995-02-05  |  19.5 KB  |  720 lines

  1. program Joy_ctrl;
  2.  
  3. uses   Winapi
  4.      , WinTypes
  5.      , WinProcs
  6.      , OWindows
  7.      , ODialogs
  8.      , MMSystem
  9.      , Validate
  10.      , Strings
  11.      , Ctl3D
  12.      ;
  13.  
  14. {$R Joy_ctrl.res}
  15.  
  16. const
  17.  
  18. { Resource IDs }
  19.  
  20.   id_Dialog = 10;
  21.   id_Menu = 20;
  22.   idd_x = 101;
  23.   idd_y = 102;
  24.  
  25. { Menu item IDs }
  26.  
  27.   idm_output_none = 201;
  28.   idm_start = 300;
  29.   idm_stop = 400;
  30.   idm_setting = 500;
  31.  
  32.   idm_set_res = 501;
  33.   idm_set_xmov = 510;
  34.   idm_set_ymov = 511;
  35.   idm_set_abut = 520;
  36.   idm_set_bbut = 521;
  37.   idm_joypanel = 599;
  38.   { submenu positions }
  39.   mpos_output = 0;
  40.  
  41. TYPE
  42.    TMovMesg = object
  43.       bStatus, bChannel, bData1 : Byte;
  44.       fReverse : boolean;
  45.       function GetMidiMsg(jpos:WORD):LongInt;
  46.    end;
  47.  
  48.    TButtMesg = object
  49.       bStatus, bChannel, bData1 : Byte;
  50.       iLow, iHigh : integer;
  51.       function GetMidiMsg(bpos:WORD):LongInt;
  52.    end;
  53.  
  54.    TMidiMsg = record
  55.      case integer of
  56.      0: (msg_db : array [0..3] of Byte );
  57.      1: (msg_dw : LongInt);
  58.    end;
  59.  
  60. { TJoyCtrl is the main window of the application }
  61.  
  62.   PJoyCtrl = ^TJoyCtrl;
  63.   TJoyCtrl = object(TDlgWindow)
  64.  
  65.     wOutputNums : integer;
  66.     wCurOutput  : integer;
  67.     hmod : HMIDI;
  68.  
  69.     psx : PStatic;
  70.     psy : PStatic;
  71.  
  72.     fStarted : Boolean;
  73.  
  74.     jsThr : WORD;
  75.     jsPeriod : WORD;
  76.  
  77.     xmidmsg, ymidmsg : TMovMesg;
  78.     lastXmsg,lastYmsg : LongInt;
  79.     amidmsg, bmidmsg : TButtMesg;
  80.  
  81.     constructor Init;
  82.     destructor done; virtual;
  83.     procedure SetupWindow; virtual;
  84.     function GetClassName: PChar; virtual;
  85.     procedure GetWindowClass(var AWndClass: TWndClass); virtual;
  86.  
  87.     procedure SetupOutputs;
  88.     procedure SetOutput(newCurOutput:integer);
  89.  
  90.     procedure OpenOutput;
  91.     procedure CloseOutput;
  92.  
  93.     procedure wmCommand(var Msg:TMessage); virtual wm_first+wm_command;
  94.  
  95.     procedure wmJoy1ButtonDown(var Msg:TMessage); virtual wm_first + MM_JOY1BUTTONDOWN;
  96.     procedure wmJoy1ButtonUp  (var Msg:TMessage); virtual wm_first + MM_JOY1BUTTONUP;
  97.     procedure wmJoy1Move      (var Msg:TMessage); virtual wm_first + MM_JOY1MOVE;
  98.  
  99.     procedure cmStart(var Msg:TMessage); virtual cm_first + idm_start;
  100.     procedure cmStop(var Msg:TMessage); virtual cm_first + idm_stop;
  101.  
  102.     procedure cmRes(var Msg:TMessage); virtual cm_first + idm_set_res;
  103.     procedure cmXMov(var Msg:TMessage); virtual cm_first + idm_set_xmov;
  104.     procedure cmYMov(var Msg:TMessage); virtual cm_first + idm_set_ymov;
  105.     procedure cmABut(var Msg:TMessage); virtual cm_first + idm_set_abut;
  106.     procedure cmBBut(var Msg:TMessage); virtual cm_first + idm_set_bbut;
  107.     procedure cmJoyPanel(var Msg:TMessage); virtual cm_first + idm_joypanel;
  108.  
  109.     procedure MovDlg(var midmsg: TMovMesg;ATitle:PChar);
  110.     procedure ButtDlg(var midmsg: TButtMesg;ATitle:PChar);
  111.  
  112.     procedure InitProfile;
  113.     procedure WriteProfile;
  114.   end;
  115.  
  116. { TJoyCtrlApp is the application object. It creates a main window of
  117.   type TJoyCtrl. }
  118.  
  119.   TJoyCtrlApp = object(TApplication)
  120.     procedure InitMainWindow; virtual;
  121.   end;
  122.  
  123.  
  124. function TMovMesg.GetMidiMsg(jpos:WORD):LongInt;
  125. var msg : TMidiMsg;
  126. begin
  127.    msg.msg_dw := 0;
  128.    msg.msg_db[0] := bStatus or bChannel;
  129.    if fReverse then jpos := not jpos;
  130.    if bStatus < $C0 then
  131.     begin
  132.        msg.msg_db[1] := bData1 and $7F;
  133.        jpos := jpos shr 9;
  134.        msg.msg_db[2] := jpos and $7F;
  135.     end
  136.    else
  137.     if bStatus < $E0 then { Pgm or Aftertouch }
  138.      begin
  139.        jpos := jpos shr 9;
  140.        msg.msg_db[1] := jpos and $7F;
  141.      end
  142.     else { Pitch Bend }
  143.      begin
  144.        jpos := jpos shr 2;
  145.        msg.msg_db[1] := jpos and $7F;
  146.        jpos := jpos shr 7;
  147.        msg.msg_db[2] := jpos and $7F;
  148.      end;
  149.  
  150.    GetMidiMsg := msg.msg_dw;
  151. end;
  152.  
  153. function TButtMesg.GetMidiMsg(bpos:WORD):LongInt;
  154. var msg : TMidiMsg;
  155.     iData2 : integer;
  156. begin
  157.    msg.msg_dw := 0;
  158.    if bpos=0 then iData2:=iHigh else iData2:=iLow ;
  159.    msg.msg_db[0] := bStatus or bChannel;
  160.    if bStatus < $C0 then
  161.     begin
  162.        msg.msg_db[1] := bData1 and $7F;
  163.        msg.msg_db[2] := iData2 and $7F;
  164.     end
  165.    else
  166.     if bStatus < $E0 then { Pgm or Aftertouch }
  167.        msg.msg_db[1] := iData2 and $7F
  168.     else { Pitch Bend }
  169.      begin
  170.        msg.msg_db[1] := iData2 and $7F;
  171.        msg.msg_db[2] := (iData2 shr 7) and $7F;
  172.      end;
  173.  
  174.    GetMidiMsg := msg.msg_dw;
  175. end;
  176.  
  177. { TJoyCtrl }
  178.  
  179. { Convert dialog constructor. }
  180.  
  181. constructor TJoyCtrl.Init;
  182. begin
  183.   TDlgWindow.Init(nil, PChar(id_Dialog));
  184.   wOutputNums := 0;
  185.   wCurOutput := 0;
  186.   hmod := 0;
  187.   psx := New(PStatic,InitResource(@self,idd_x,10));
  188.   psy := New(PStatic,InitResource(@self,idd_y,10));
  189.   fStarted := false;
  190.   jsThr := 0;
  191.   jsPeriod := 50;
  192.   FillChar(xmidmsg,sizeof(xmidmsg),0);
  193.   FillChar(ymidmsg,sizeof(ymidmsg),0);
  194.   FillChar(amidmsg,sizeof(amidmsg),0);
  195.   FillChar(bmidmsg,sizeof(bmidmsg),0);
  196.   LastXMsg := 0;
  197.   LastYMsg := 0;
  198. end;
  199.  
  200. destructor TJoyCtrl.Done;
  201. var i:integer;
  202. begin
  203.   if fstarted then JoyReleaseCapture(JOYSTICKID1);
  204.   CloseOutput;
  205.   WriteProfile;
  206.   TDlgWindow.Done;
  207. end;
  208. { SetupWindow is called right after the Convert dialog is created. }
  209.  
  210. procedure TJoyCtrl.SetupWindow;
  211. var i:integer;
  212.     mh : THandle;
  213. begin
  214.    inherited SetupWindow;
  215.    InitProfile;
  216.    SetupOutputs;
  217.    SetOutput(0);
  218. end;
  219.  
  220.  
  221. { add available Midi Outputs to Output Menu }
  222. procedure TJoyCtrl.SetupOutputs;
  223. VAR mc : TMIDIOUTCAPS;
  224.     i: integer;
  225.     h_pmenu : HMENU;
  226. begin
  227.    h_pmenu := GetSubMenu(GetMenu(hWindow),mpos_output);
  228.    wOutputNums := midiOutGetNumDevs + 1;
  229.    for i:=-1 to wOutputNums-2 do { start with MIDI_MAPPER }
  230.    begin
  231.       midiOutGetDevCaps(i,@mc,sizeof(mc));
  232.       if (h_pmenu<>0) then
  233.          AppendMenu(h_pmenu,MF_STRING,idm_output_none+2+i,mc.szPName);
  234.    end;
  235. end;
  236.  
  237. { Check Midi Output Menu }
  238. procedure TJoyCtrl.SetOutput(newCurOutput:integer);
  239. VAR
  240.     i: integer;
  241.     h_pmenu : HMENU;
  242. begin
  243.    h_pmenu := GetSubMenu(GetMenu(hWindow),mpos_output);
  244.    if newCurOutput>wOutputNums then newCurOutput:=0;
  245.    wCurOutput := newCurOutput;
  246.    for i:=0 to wOutputNums  do begin
  247.        if h_pmenu<>0 then
  248.           if i=wCurOutput then
  249.              CheckMenuItem(h_pmenu,idm_output_none+i,MF_BYCOMMAND or MF_CHECKED)
  250.           else
  251.              CheckMenuItem(h_pmenu,idm_output_none+i,MF_BYCOMMAND or MF_UNCHECKED);
  252.    end;
  253.  
  254. end;
  255.  
  256. procedure modErr(HWindow:HWnd; err:WORD; caption:PChar);
  257. var errbuf : array [0..255] of char;
  258. begin
  259.    if midiOutGetErrorText(err,errbuf,sizeof(errbuf)-1)<>0 then begin
  260.       wvsprintf(errbuf,'Unknown Error %04Xh',err);
  261.  
  262.    end;
  263.    if caption=nil then caption:='Midi Output Error';
  264.    MessageBox(HWindow,errbuf,caption,MB_ICONSTOP or MB_OK);
  265. end;
  266.  
  267. { Open Midi Output }
  268. procedure TJoyCtrl.OpenOutput;
  269. VAR err : WORD;
  270. begin
  271.    if hmod<>0 then CloseOutput;
  272.    if wCurOutput >= 1 then begin
  273.  
  274.    err := midiOutOpen(@hmod,wCurOutput-2,0,0,0);
  275.    if err<>0 then modErr(hWindow,err,'midiOutOpen');
  276.    end;
  277. end;
  278.  
  279. { Close Midi Output }
  280. procedure TJoyCtrl.CloseOutput;
  281. VAR
  282.     i: integer;
  283.     err : WORD;
  284. begin
  285.    if hmod <> 0 then begin
  286.       err := midiOutReset(hmod);
  287.       if err<>0 then modErr(hWindow,err,'midiOutReset');
  288.       err := midiOutClose(hmod);
  289.       if err<>0 then modErr(hWindow,err,'midiOutClose');
  290.       hmod := 0;
  291.   end;
  292. end;
  293.  
  294. { Return window class name. This name correspons to the class name
  295.   specified for the Convert dialog in the resource file. }
  296.  
  297. function TJoyCtrl.GetClassName: PChar;
  298. begin
  299.   GetClassName := 'JoyCtrlDlg';
  300. end;
  301.  
  302. procedure TJoyCtrl.GetWindowClass(var AWndClass: TWndClass);
  303. begin
  304.     inherited GetWindowClass(AWndClass);
  305.     AWndClass.hicon := LoadIcon(hInstance,'ICON_1');
  306. end;
  307.  
  308. {$IFDEF DEBUG}
  309. var dbgbuf: array [0..63] of char;
  310. {$ENDIF}
  311. procedure TJoyCtrl.wmJoy1ButtonDown(var Msg:TMessage);
  312. begin
  313. {$IFDEF DEBUG}
  314.    wvsprintf(dbgbuf,'J1DN %04X %04X %08lX'#13#10,Msg.Message);
  315.    OutputDebugString(dbgbuf);
  316. {$ENDIF}
  317.    if hmod<>0 then begin
  318.       if (Msg.wParam and JOY_BUTTON1CHG)<>0 then
  319.          if amidmsg.bStatus<>0 then
  320.              midiOutShortMsg(hmod,amidmsg.GetMidiMsg(0));
  321.       if (Msg.wParam and JOY_BUTTON2CHG)<>0 then
  322.          if bmidmsg.bStatus<>0 then
  323.              midiOutShortMsg(hmod,bmidmsg.GetMidiMsg(0));
  324.       end;
  325.    Msg.Result := 0;
  326. end;
  327.  
  328. procedure TJoyCtrl.wmJoy1ButtonUp  (var Msg:TMessage);
  329. begin
  330. {$IFDEF DEBUG}
  331.    wvsprintf(dbgbuf,'J1UP %04X %04X %08lX'#13#10,Msg.Message);
  332.    OutputDebugString(dbgbuf);
  333. {$ENDIF}
  334.    if hmod<>0 then begin
  335.       if (Msg.wParam and JOY_BUTTON1CHG)<>0 then
  336.          if amidmsg.bStatus<>0 then
  337.              midiOutShortMsg(hmod,amidmsg.GetMidiMsg(1));
  338.       if (Msg.wParam and JOY_BUTTON2CHG)<>0 then
  339.          if bmidmsg.bStatus<>0 then
  340.              midiOutShortMsg(hmod,bmidmsg.GetMidiMsg(1));
  341.       end;
  342.    Msg.Result := 0;
  343. end;
  344.  
  345. procedure TJoyCtrl.wmJoy1Move      (var Msg:TMessage);
  346. var tbuf : array[0..7] of char;
  347.     vpar: Word;
  348.     m : Longint;
  349.  
  350.     Function MidMsgString(mmsg:LongInt):PChar;
  351.     begin
  352.        if ((mmsg and $F0) < $C0) then
  353.           vpar := LoByte(HiWord(mmsg))
  354.        else if ((mmsg and $F0) < $E0) then
  355.           vpar := HiByte(LoWord(mmsg))
  356.        else
  357.           vpar := 128*(LoByte(Hiword(mmsg))-64) + HiByte(LoWord(mmsg));
  358.       wvsprintf(tbuf,'%3d',vpar);
  359.       MidMsgString:=tbuf;
  360.     end;
  361. begin
  362. {$IFDEF DEBUG}
  363.    wvsprintf(dbgbuf,'J1MV %04X %04X %08lX'#13#10,Msg.Message);
  364.    OutputDebugString(dbgbuf);
  365. {$ENDIF}
  366. (*
  367.    wvsprintf(tbuf,'X %5u',Msg.LParamLo);
  368.    psx^.SetText(tbuf);
  369.    wvsprintf(tbuf,'Y %5u',Msg.LParamHi);
  370.    psy^.SetText(tbuf);
  371. *)
  372.    if hmod<>0 then begin
  373.       if xmidmsg.bStatus<>0 then begin
  374.          m := xmidmsg.GetMidiMsg(Msg.LParamLo);
  375.          if m<>LastXMsg then begin
  376.             midiOutShortMsg(hmod,m);
  377.             LastXMsg := m;
  378.             psx^.SetText(MidMsgString(m));
  379.          end;
  380.       end;
  381.       if ymidmsg.bStatus<>0 then begin
  382.          m := ymidmsg.GetMidiMsg(Msg.LParamHi);
  383.          if m<>LastYMsg then begin
  384.             midiOutShortMsg(hmod,m);
  385.             LastYMsg := m;
  386.             psy^.SetText(MidMsgString(m));
  387.          end;
  388.       end;
  389.    end;
  390.  
  391.    Msg.Result := 0;
  392. end;
  393.  
  394. { dispatch Midi Output Menu Commands }
  395. procedure TJoyCtrl.wmCommand(var Msg:TMessage);
  396. var i:integer;
  397. BEGIN
  398.    if (Msg.LParam = 0) then begin { a menu command }
  399.       i := Msg.WParam - idm_output_none;
  400.       if ( i >= 0) and ( i <= wOutputNums ) then begin
  401.          SetOutput(i);
  402.          OpenOutput;
  403.          Msg.Result := 0;
  404.          exit;
  405.       end;
  406.    end;
  407.    inherited wmCommand(Msg);
  408. END;
  409.  
  410. procedure TJoyCtrl.cmStart(var Msg:TMessage);
  411. var hm : HMenu;
  412. begin
  413.    if not fStarted then begin
  414.       fStarted := JoySetCapture(hWindow,JOYSTICKID1,jsPeriod,true)=0;
  415.       joySetThreshold(JOYSTICKID1,jsThr);
  416.       end;
  417.    if fStarted then begin
  418.       hm := GetMenu(hWindow);
  419.       EnableMenuItem(hm,idm_stop,MF_BYCOMMAND or MF_ENABLED);
  420.       EnableMenuItem(hm,idm_start,MF_BYCOMMAND or MF_GRAYED );
  421.       SetMenu(hWindow,hm);
  422.    end;
  423.    Msg.Result := 1;
  424. end;
  425.  
  426. procedure TJoyCtrl.cmStop(var Msg:TMessage);
  427. var hm : HMenu;
  428. begin
  429.    if fStarted then begin
  430.       JoyReleaseCapture(JOYSTICKID1);
  431.       hm := GetMenu(hWindow);
  432.       EnableMenuItem(hm,idm_stop,MF_BYCOMMAND or MF_GRAYED );
  433.       EnableMenuItem(hm,idm_start,MF_BYCOMMAND or MF_ENABLED);
  434.       SetMenu(hWindow,hm);
  435.    end;
  436.    fStarted := false;
  437.  
  438.    Msg.Result := 1;
  439. end;
  440.  
  441. procedure TJoyCtrl.cmRes(var Msg:TMessage);
  442. var D : PDialog;
  443.     E : PEdit;
  444.     jc : TJOYCAPS;
  445.     trans_buf : record
  446.        e_thres : array [0..7] of char;
  447.        e_res : array [0..7] of char;
  448.     end;
  449.     r:integer;
  450. begin
  451.    if joyGetDevCaps(JOYSTICKID1,@jc,sizeof(jc))<>0 then exit;
  452.    D := New(PDialog, Init(@Self, 'JOYRES'));
  453.    E := New(PEdit, InitResource(D,102,sizeof(trans_buf.e_thres)));
  454.    E^.SetValidator( New(PRangeValidator,Init(0,65535)));
  455.    wvsprintf(trans_buf.e_thres,'%u',jsThr);
  456.    E := New(PEdit, InitResource(D,104,sizeof(trans_buf.e_res)));
  457.    E^.SetValidator( New(PRangeValidator,Init(jc.wPeriodMin,jc.WPeriodMax)));
  458.    wvsprintf(trans_buf.e_res,'%u',jsPeriod);
  459.    D^.TransferBuffer := @trans_buf;
  460.    if Application^.ExecDialog(D)=IDOK then
  461.    begin
  462.       Val(trans_buf.e_thres,jsThr,r);
  463.       Val(trans_buf.e_res,jsPeriod,r);
  464.       if fStarted then begin
  465.          {joyReleaseCapture(JOYSTICKID1);
  466.          joySetCapture(JOYSTICKID1,hWindow,jsPeriod,true);
  467.          joySetThreshold(JOYSTICKID1,jsThr);
  468.          }
  469.          cmStop(Msg);
  470.          cmStart(Msg);
  471.       end;
  472.    end;
  473. end;
  474.  
  475. procedure TJoyCtrl.cmXMov(var Msg:TMessage);
  476. begin
  477.    MovDlg(xmidmsg,'X Axis');
  478. end;
  479. procedure TJoyCtrl.cmYMov(var Msg:TMessage);
  480. begin
  481.    MovDlg(ymidmsg,'Y Axis');
  482. end;
  483. procedure TJoyCtrl.cmABut(var Msg:TMessage);
  484. begin
  485.    ButtDlg(amidmsg,'A Button');
  486. end;
  487. procedure TJoyCtrl.cmBBut(var Msg:TMessage);
  488. begin
  489.    ButtDlg(bmidmsg,'B Button');
  490. end;
  491.  
  492. procedure TJoyCtrl.cmJoyPanel(var Msg:TMessage);
  493. begin
  494.    WinExec('control joystick.cpl',SW_SHOW);
  495. end;
  496.  
  497. procedure TJoyCtrl.MovDlg(var midmsg: TMovMesg; ATitle : PChar);
  498. const StatBytes : array[0..6] of byte = (0,$90,$A0,$B0,$C0,$D0,$E0);
  499. var D : PDialog;
  500.     E : PEdit;
  501.     P : Pointer;
  502.     S : PStatic;
  503.     trans : record
  504.        e_chn : array[0..5] of char;
  505.        e_d1 : array[0..5] of char;
  506.        r_rev : Wordbool;
  507.        r_ev : array[0..6] of Wordbool;
  508.        s_titl : array [0..9] of char;
  509.     end;
  510.     i,r : integer;
  511. begin
  512.    D := New (PDialog,Init(@self,'MOVMSG'));
  513.    E := New(PEdit,InitResource(D,141,sizeof(trans.e_chn)));
  514.    E^.SetValidator( New(PRangeValidator,Init(1,16)));
  515.    i:=midmsg.bChannel + 1;
  516.    wvsprintf(trans.e_chn,'%d',i);
  517.    E := New(PEdit,InitResource(D,111,sizeof(trans.e_d1)));
  518.    E^.SetValidator( New(PRangeValidator,Init(0,127)));
  519.    i:=midmsg.bData1;
  520.    wvsprintf(trans.e_d1,'%d',i);
  521.    P:=New(PCheckBox,InitResource(D,121));
  522.    trans.r_rev := midmsg.fReverse;
  523.    for i:=0 to 6 do begin
  524.        trans.r_ev[i] := (midmsg.bStatus = StatBytes[i]);
  525.        P:=New(PRadioButton,InitResource(D,101+i));
  526.    end;
  527.  
  528.    StrLCopy(trans.s_titl,ATitle,sizeof(trans.s_titl));
  529.    S := New(PStatic, InitResource(D,160,sizeof(trans.s_titl)));
  530.  
  531.    D^.TransferBuffer := @trans;
  532.    if Application^.ExecDialog(D)=IDOK then begin
  533.       Val(trans.e_chn,i,r);
  534.       midmsg.bChannel := i-1;
  535.       Val(trans.e_d1,i,r);
  536.       midmsg.bData1 := i;
  537.       midmsg.fReverse := trans.r_rev;
  538.       for i:=0 to 6 do begin
  539.           if trans.r_ev[i] then midmsg.bStatus := StatBytes[i];
  540.       end;
  541.    end;
  542. end;
  543.  
  544. procedure TJoyCtrl.ButtDlg(var midmsg: TButtMesg;ATitle:PChar);
  545. const StatBytes : array[0..6] of byte = (0,$90,$A0,$B0,$C0,$D0,$E0);
  546. var D : PDialog;
  547.     E : PEdit;
  548.     P : Pointer;
  549.     S : PStatic;
  550.     trans : record
  551.        e_chn : array[0..5] of char;
  552.        e_d1 : array[0..5] of char;
  553.        e_up : array[0..7] of char;
  554.        e_dn : array[0..7] of char;
  555.        r_ev : array[0..6] of Wordbool;
  556.        s_titl : array [0..9] of char;
  557.     end;
  558.     i,r : integer;
  559. begin
  560.    D := New (PDialog,Init(@self,'BUTMSG'));
  561.    E := New(PEdit,InitResource(D,141,sizeof(trans.e_chn)));
  562.    E^.SetValidator( New(PRangeValidator,Init(1,16)));
  563.    i:=midmsg.bChannel + 1;
  564.    wvsprintf(trans.e_chn,'%d',i);
  565.    E := New(PEdit,InitResource(D,111,sizeof(trans.e_d1)));
  566.    E^.SetValidator( New(PRangeValidator,Init(0,127)));
  567.    i:=midmsg.bData1;
  568.    wvsprintf(trans.e_d1,'%d',i);
  569.    E := New(PEdit,InitResource(D,121,sizeof(trans.e_up)));
  570.    E^.SetValidator( New(PRangeValidator,Init(-8192,8191)));
  571.    wvsprintf(trans.e_up,'%d',midmsg.ihigh);
  572.    E := New(PEdit,InitResource(D,122,sizeof(trans.e_dn)));
  573.    E^.SetValidator( New(PRangeValidator,Init(-8192,8191)));
  574.    wvsprintf(trans.e_dn,'%d',midmsg.ilow);
  575.    for i:=0 to 6 do begin
  576.        trans.r_ev[i] := (midmsg.bStatus = StatBytes[i]);
  577.        P:=New(PRadioButton,InitResource(D,101+i));
  578.    end;
  579.  
  580.    StrLCopy(trans.s_titl,ATitle,sizeof(trans.s_titl));
  581.    S := New(PStatic, InitResource(D,160,sizeof(trans.s_titl)));
  582.  
  583.    D^.TransferBuffer := @trans;
  584.    if Application^.ExecDialog(D)=IDOK then begin
  585.       Val(trans.e_chn,i,r);
  586.       midmsg.bChannel := i-1;
  587.       Val(trans.e_d1,i,r);
  588.       midmsg.bData1 := i;
  589.       Val(trans.e_up,midmsg.iHigh,r);
  590.       Val(trans.e_dn,midmsg.iLow,r);
  591.       for i:=0 to 6 do begin
  592.           if trans.r_ev[i] then midmsg.bStatus := StatBytes[i];
  593.       end;
  594.    end;
  595. end;
  596.  
  597. const AppName : PChar = 'MidiJoy';
  598.  
  599.       szRes : PChar = 'Resolution';
  600.       szPeriod : PChar = 'Period';
  601.  
  602.       szXStatus : PChar = 'Xmsg';
  603.       szXchn : PChar = 'XChn';
  604.       szXData : PChar = 'XData';
  605.       szXrev : PChar = 'Xrev';
  606.  
  607.       szYStatus : PChar = 'Ymsg';
  608.       szYchn : PChar = 'YChn';
  609.       szYData : PChar = 'YData';
  610.       szYrev : PChar = 'Yrev';
  611.  
  612.       szAStatus : PChar = 'Amsg';
  613.       szAchn : PChar = 'AChn';
  614.       szAData : PChar = 'AData';
  615.       szAup : PChar = 'Aup';
  616.       szAdown : PChar = 'Adown';
  617.  
  618.       szBStatus : PChar = 'Bmsg';
  619.       szBchn : PChar = 'BChn';
  620.       szBData : PChar = 'BData';
  621.       szBup : PChar = 'Bup';
  622.       szBdown : PChar = 'Bdown';
  623.  
  624.  
  625. procedure TJoyCtrl.InitProfile;
  626.    function GetInt(key:PChar;def:integer):integer;
  627.    begin
  628.       GetInt:=Integer(GetProfileInt(AppName,key,def));
  629.    end;
  630. begin
  631.    jsThr := GetInt(szRes,0);
  632.    jsPeriod := GetInt(szPeriod,50);
  633.  
  634.    xmidmsg.bStatus:=GetInt(szXStatus,$B0);
  635.    xmidmsg.bChannel:=GetInt(szXchn,1)-1;
  636.    xmidmsg.bData1:=GetInt(szXData,1);
  637.    xmidmsg.fReverse:=(GetInt(szXrev,0)=1);
  638.  
  639.    ymidmsg.bStatus:=GetInt(szYStatus,$E0);
  640.    ymidmsg.bChannel:=GetInt(szYchn,1)-1;
  641.    ymidmsg.bData1:=GetInt(szYData,0);
  642.    ymidmsg.fReverse:=(GetInt(szYrev,1)=1);
  643.  
  644.    amidmsg.bStatus:=GetInt(szAStatus,$B0);
  645.    amidmsg.bChannel:=GetInt(szAchn,1)-1;
  646.    amidmsg.bData1:=GetInt(szAData,64);
  647.    amidmsg.iLow := GetInt(szAup,0);
  648.    amidmsg.iHigh:= GetInt(szAdown,127);
  649.  
  650.    bmidmsg.bStatus:=GetInt(szBStatus,$B0);
  651.    bmidmsg.bChannel:=GetInt(szBchn,1)-1;
  652.    bmidmsg.bData1:=GetInt(szBData,64);
  653.    bmidmsg.iLow := GetInt(szBup,0);
  654.    bmidmsg.iHigh:= GetInt(szBdown,127);
  655.  
  656. end;
  657.  
  658. procedure TJoyCtrl.WriteProfile;
  659.    procedure WriteInt(key:PChar;value:integer);
  660.    var buf:array [0..7] of char;
  661.    begin
  662.       wvsprintf(buf,'%d',value);
  663.       WriteProfileString(AppName,key,buf);
  664.    end;
  665.    procedure WriteHex(key:PChar;value:integer);
  666.    var buf:array [0..7] of char;
  667.    begin
  668.       wvsprintf(buf,'0x%x',value);
  669.       WriteProfileString(AppName,key,buf);
  670.    end;
  671.  
  672. begin
  673.    WriteInt(szRes,jsThr);
  674.    WriteInt(szPeriod,jsPeriod);
  675.  
  676.    WriteHex(szXStatus,xmidmsg.bStatus);
  677.    WriteInt(szXchn,   xmidmsg.bChannel+1);
  678.    WriteInt(szXData,  xmidmsg.bData1);
  679.    WriteInt(szXrev,   integer(xmidmsg.fReverse));
  680.  
  681.    WriteHex(szYStatus,ymidmsg.bStatus);
  682.    WriteInt(szYchn,   ymidmsg.bChannel+1);
  683.    WriteInt(szYData,  ymidmsg.bData1);
  684.    WriteInt(szYrev,   integer(ymidmsg.fReverse));
  685.  
  686.    WriteHex(szAStatus,amidmsg.bStatus);
  687.    WriteInt(szAchn,   amidmsg.bChannel+1);
  688.    WriteInt(szAData,  amidmsg.bData1);
  689.    WriteInt(szAup,    amidmsg.iLow);
  690.    WriteInt(szAdown,  amidmsg.iHigh);
  691.  
  692.    WriteHex(szBStatus,bmidmsg.bStatus);
  693.    WriteInt(szBchn,   bmidmsg.bChannel+1);
  694.    WriteInt(szBData,  bmidmsg.bData1);
  695.    WriteInt(szBup,    bmidmsg.iLow);
  696.    WriteInt(szBdown,  bmidmsg.iHigh);
  697. end;
  698. { TJoyCtrlApp }
  699.  
  700. { Create a Midimon dialog as the application's main window. }
  701.  
  702. procedure TJoyCtrlApp.InitMainWindow;
  703. begin
  704.   MainWindow := New(PJoyCtrl, Init);
  705. end;
  706.  
  707. var
  708.   JoyCtrlApp: TJoyCtrlApp;
  709.  
  710. begin
  711.    Ctl3dRegister(HInstance);
  712.    Ctl3dAutoSubclass(HInstance);
  713.  
  714.   JoyCtrlApp.Init('JoyCtrlApp');
  715.   JoyCtrlApp.Run;
  716.   JoyCtrlApp.Done;
  717.  
  718.    Ctl3dUnregister(HInstance);
  719. end.
  720.