home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / PASWIZ13.ZIP / PASWIZ.DOC < prev    next >
Encoding:
Text File  |  1992-11-14  |  42.9 KB  |  1,235 lines

  1.                   The Pascal Wizard's Library
  2.                   =-------------------------=
  3.                           Version 1.3
  4.  
  5.     PasWiz  Copyright (c) 1990-1992  Thomas G. Hanlin III
  6.  
  7.  
  8.  
  9. This is PasWiz, a library of assorted routines for use with
  10. Turbo Pascal, Quick Pascal, and compatible compilers.  Full
  11. Pascal source code is now included with the shareware version.
  12. Assembly language sources are provided to registered owners.
  13. The PasWiz collection is copyrighted, but may be distributed as
  14. long as the following conditions are met:
  15.  
  16.    All PasWiz files must be distributed together as a unit in
  17.    unmodified form.  No files may be left out or added.
  18.  
  19. You use this library at your own risk.  It has been tested by
  20. me on my own computer, but I will not assume any responsibility
  21. for any problems which PasWiz may cause you.  If you do
  22. encounter a problem, please let me know about it, and I will do
  23. my best to verify and repair the error.
  24.  
  25. It is expected that if you find PasWiz useful, you will
  26. register your copy. You may not use PasWiz routines in programs
  27. intended for sale unless you have registered.  Registration
  28. entitles you to receive the latest version of PasWiz, complete
  29. with full source code.  See the file ORDER.FRM for details.
  30.  
  31. Warning: Use of the PasWiz library for more than 30 days
  32. without registering has been determined to cause cancer in
  33. people who eat cigarettes!
  34.  
  35. So who's the Pascal Wizard?  With PasWiz, you are!  Read this
  36. tome well, for invoking these routines without proper
  37. preparation may bring unexpected results.  Cape and hat
  38. (optional) not included.
  39.  
  40.                       Table of Contents                  page 2
  41.  
  42.  
  43.  
  44.  Overview and Legal Info .................................... 1
  45.  
  46.  BCD Math ................................................... 3
  47.  
  48.  Equipment Info ............................................. 7
  49.  
  50.  Expression Evaluator ...................................... 10
  51.  
  52.  Extensions to Pascal's Math ............................... 11
  53.  
  54.  Keyboard Control .......................................... 13
  55.  
  56.  String Stuff .............................................. 17
  57.  
  58.  Music ..................................................... 21
  59.  
  60.  Mouse ..................................................... 22
  61.  
  62.                            BCD Math                      page 3
  63.  
  64.                            Unit: BCD
  65.  
  66.  
  67.  
  68. Some of you may not have heard of BCD math, or at least not
  69. have more than a passing acquaintance with the subject.  BCD
  70. (short for Binary-Coded Decimal) is a way of encoding numbers.
  71. It differs from the normal method of handling numbers in
  72. several respects.  On the down side, BCD math is much slower
  73. than normal math and the numbers take up more memory.  However,
  74. the benefits may far outweigh these disadvantages, depending on
  75. your application: BCD math is absolutely precise within your
  76. desired specifications, and you can make a BCD number as large
  77. as you need.  If your applications don't require great range or
  78. precision out of numbers, normal Pascal math is probably the
  79. best choice. For scientific applications, accounting,
  80. engineering and other demanding tasks, though, BCD may be just
  81. the thing you need.
  82.  
  83. The BCD math routines provided by PasWiz allow numbers of up to
  84. 255 digits long (the sign counts as a digit, but the decimal
  85. point doesn't).  You may set the decimal point to any position
  86. you like, as long as there is at least one digit position to
  87. the left of the decimal.
  88.  
  89. Since Pascal doesn't support BCD numbers directly, we store the
  90. BCD numbers in strings.  The results are not in text format and
  91. won't mean much if displayed.  A conversion routine allows you
  92. to change a BCD number to a text string in any of a variety of
  93. formats.
  94.  
  95. Note that the BCD math handler doesn't yet track
  96. overflow/underflow error conditions.  If you anticipate that
  97. this may be a problem, it would be a good idea to screen your
  98. input or to make the BCD range large enough to avoid these
  99. errors.
  100.  
  101. Let's start off by considering the BCD range.  This is kept in
  102. two integer variables, LDigits and RDigits, which can be
  103. accessed by your program. These variables specify the maximum
  104. number of digits to the left and to the right of the decimal
  105. point.  There must be at least one digit on the left, and the
  106. total number of digits must be less than 255.  The BCD strings
  107. will have a length that's one larger than the total number of
  108. digits, to account for the sign of the number.  The decimal
  109. point is implicit and doesn't take up any extra space.
  110.  
  111. It is assumed that you will only use one size of BCD number in
  112. your program-- there are no provisions for handling
  113. mixed-length BCD numbers.  Of course, you could manage that
  114. yourself with a little extra work, if it seems like a useful
  115. capability.  If you don't change LDigits or RDigits, the
  116. default size of the BCD numbers will be 32 (20 to the left, 11
  117. to the right, 1 for the sign).
  118.  
  119.                            BCD Math                      page 4
  120.  
  121.                            Unit: BCD
  122.  
  123.  
  124.  
  125. Before doing any BCD calculations, you must have some BCD
  126. numbers!  The BCDSet routine takes a number in text string form
  127. and converts it to BCD:
  128.  
  129. TextSt := '1234567890.50';
  130. Nr := BCDSet(TextSt);
  131.    { FUNCTION BCDSet (TextSt: String): String; }
  132.  
  133. If your numbers are stored as actual numbers, you can convert
  134. them to a text string with Pascal's Str procedure, then to BCD:
  135.  
  136. Str(Number, TextSt);
  137. Nr := BCDSet(TextSt);
  138.  
  139. BCD numbers can also be converted back to text strings, of
  140. course.  You may specify how many digits to the right of the
  141. decimal to keep (the number will be truncated, not rounded).
  142. If the RightDigits value is positive, trailing zeros will be
  143. kept; if negative, trailing zeros will be removed.  There are
  144. also various formatting options which may be used.  Here's how
  145. it works:
  146.  
  147. FUNCTION BCDFormat (Nr: String; HowToFormat,
  148.                     RightDigits: Integer): String;
  149.  
  150. The HowToFormat value may be any combination of the following
  151. (just add the numbers of the desired formats together):
  152.  
  153.    0   plain number
  154.    1   use commas to separate thousands, etc
  155.    2   start number with a dollar sign
  156.    4   put the sign on the right instead of the left side
  157.    8   use plus sign instead of space if nr is not negative
  158.  
  159. The BCD math functions are pretty much self-explanatory, so
  160. I'll keep the descriptions brief.  The single-parameter
  161. functions are listed on the next page.
  162.  
  163.                            BCD Math                      page 5
  164.  
  165.                            Unit: BCD
  166.  
  167.  
  168.  
  169. { absolute value }
  170. FUNCTION BCDAbs (Nr: String): String;
  171.  
  172. { cosine }
  173. FUNCTION BCDCos (Nr: String): String;
  174.  
  175. { cotangent }
  176. FUNCTION BCDCot (Nr: String): String;
  177.  
  178. { cosecant }
  179. FUNCTION BCDCsc (Nr: String): String;
  180.  
  181. { convert degrees to radians }
  182. FUNCTION BCDDeg2Rad (Nr: String): String;
  183.  
  184. { the constant "e" }
  185. FUNCTION BCDe: String;
  186.  
  187. { factorial }
  188. FUNCTION BCDFact (Nr: Integer): String;
  189.  
  190. { fractional part of number }
  191. FUNCTION BCDFrac (Nr: String): String;
  192.  
  193. { integer part of number }
  194. FUNCTION BCDInt (Nr: String): String;
  195.  
  196. { negation }
  197. FUNCTION BCDNeg (Nr: String): String;
  198.  
  199. { the constant "pi" }
  200. FUNCTION BCDpi: String;
  201.  
  202. { convert radians to degrees }
  203. FUNCTION BCDRad2Deg (Nr: String): String;
  204.  
  205. { secant }
  206. FUNCTION BCDSec (Nr: String): String;
  207.  
  208. { signum }
  209. FUNCTION BCDSgn (Nr: String): Integer;
  210.  
  211. { sine }
  212. FUNCTION BCDSin (Nr: String): String;
  213.  
  214. { square root }
  215. FUNCTION BCDSqrt (Nr: String): String;
  216.  
  217. { tangent }
  218. FUNCTION BCDTan (Nr: String): String;
  219.  
  220.                            BCD Math                      page 6
  221.  
  222.                            Unit: BCD
  223.  
  224.  
  225.  
  226. Notes on the single-parameter functions:
  227.  
  228.   The signum function returns an integer based on the sign of
  229.   the BCD number:
  230.  
  231.      -1   if the BCD number is negative
  232.       0   if the BCD number is zero
  233.       1   if the BCD number is positive
  234.  
  235.   BCDpi is accurate to the maximum level afforded by the BCD
  236.   functions. BCDe is accurate to as many as 115 decimal
  237.   places.  The actual accuracy, of course, depends on the size
  238.   of BCD numbers you've chosen.
  239.  
  240.   The trigonometric functions (cos, sin, tan, sec, csc, cot)
  241.   expect angles in radians.  BCDDeg2Rad and BCDRad2Deg will
  242.   allow you to convert back and forth between radians and
  243.   degrees.
  244.  
  245.  
  246.  
  247. Here is a list of the two-parameter functions:
  248.  
  249.  
  250. { addition }
  251. FUNCTION BCDAdd (Nr1, Nr2: String): String;
  252.  
  253. { divide 1st by 2nd }
  254. FUNCTION BCDDiv (Nr1, Nr2: String): String;
  255.  
  256. { multiplication }
  257. FUNCTION BCDMul (Nr1, Nr2: String): String;
  258.  
  259. { subtract 2nd from 1st }
  260. FUNCTION BCDSub (Nr1, Nr2: String): String;
  261.  
  262. { raise to a power }
  263. FUNCTION BCDPower (Nr: String; Power: Integer): String;
  264.  
  265. { compare two numbers }
  266. FUNCTION BCDCompare (Nr1, Nr2: String): Integer;
  267.  
  268. The comparison function returns an integer which reflects how
  269. the two numbers compare to each other:
  270.  
  271.    -1   Nr1 < Nr2
  272.     0   Nr1 = Nr2
  273.     1   Nr1 > Nr2
  274.  
  275.                         Equipment Info                   page 7
  276.  
  277.                         Unit: Equipment
  278.  
  279.  
  280.  
  281. The equipment unit gives you information about the computing
  282. environment. This includes both installed software and hardware.
  283.  
  284. The first function allows you to determine if an "enhanced"
  285. keyboard (101-key) is installed.  It may not be able to figure
  286. out what the keyboard is on some older not-quite-clone PCs, in
  287. which case it will take the safe way out and report that there
  288. is no enhanced keyboard.  This function returns -1 if there is
  289. an enhanced keyboard present, 0 if not.
  290.  
  291. FUNCTION EnhKbd: Integer;
  292.  
  293. Want to know the type of processor (CPU) being used?  Can do!
  294.  
  295. FUNCTION Processor: Integer;
  296.  
  297. The results will be reported as a number which can be decoded
  298. as follows:
  299.  
  300.    0    NEC V20
  301.    1    8088 or 8086
  302.    2    80186
  303.    3    80286
  304.    4    80386
  305.    5    80486
  306.  
  307. Maybe you'd like to check for a CD-ROM drive:
  308.  
  309. FUNCTION CDROM: Integer;
  310.  
  311. This tells you how many logical drives exist, if there is a
  312. CD-ROM available. If not, it will return 0.  Note that the
  313. CD-ROM installation check conflicts with the GRAPHICS.COM
  314. installation check for DOS 4.0, due to some screw-up at IBM or
  315. Microsoft.  I'm not yet sure whether DOS 5.0 is similarly
  316. afflicted.
  317.  
  318. The number of floppy drives installed is retrieved with this:
  319.  
  320. FUNCTION Floppies: Integer;
  321.  
  322. To get the number of serial (COM) ports and parallel (LPT)
  323. ports, use the following functions:
  324.  
  325. FUNCTION CommPorts: Integer;
  326.  
  327. FUNCTION PrtPorts: Integer;
  328.  
  329.                         Equipment Info                   page 8
  330.  
  331.                         Unit: Equipment
  332.  
  333.  
  334.  
  335. Now, there may be up to four floppy drives in a system;
  336. however, the AT CMOS data area only directly supports two.
  337. This makes it easy to find out what kind of drives the first
  338. two are, but not the second two, if any.  Such is life.
  339.  
  340. PROCEDURE FloppyType (VAR Drive1, Drive2: Integer);
  341.  
  342. The results from FloppyType are returned as follows:
  343.  
  344.    0    no drive
  345.    1    5 1/4"    360K
  346.    2    5 1/4"    1.2M
  347.    3    3 1/2"    720K
  348.    4    3 1/2"    1.44M
  349.  
  350. Result codes of 5-7 are available, but not yet defined.  One
  351. might guess that the 2.88M drive supported by DOS 5.0 will be
  352. drive type 5.  If anyone knows for sure, speak up!
  353.  
  354. New memory types sure have burgeoned over the years...
  355. expanded, extended, and now XMS.  There are routines to check
  356. all of these:
  357.  
  358. { amount of extended memory installed }
  359. FUNCTION AllExtMem: LongInt;
  360.  
  361. { BIOS extended memory available }
  362. FUNCTION GetExtM: LongInt
  363.  
  364. { amount of expanded memory  (a page is 16 Kbytes) }
  365. PROCEDURE GetEMSm (VAR TotalPages, FreePages: Integer);
  366.  
  367. { amount of XMS memory  (returned in kilobytes) }
  368. PROCEDURE GetXMSm (VAR LargestFreeBlock, TotalFree: LongInt);
  369.  
  370. When you're dealing with extended memory, whether it be
  371. BIOS-type or using the XMS standard, the results are returned
  372. in kilobytes.  Multiply 'em by 1024 to convert to bytes.  When
  373. you're dealing with expanded memory (EMS), the results are in
  374. pages of 16,384 bytes.
  375.  
  376.                         Equipment Info                   page 9
  377.  
  378.                         Unit: Equipment
  379.  
  380.  
  381.  
  382. A few more routines to get the versions of the EMS and XMS
  383. drivers, if any:
  384.  
  385. PROCEDURE GetEMSv (VAR MajorV, MinorV: Integer);
  386.  
  387. PROCEDURE GetXMSv (VAR MajorV, MinorV: Integer);
  388.  
  389. These return the major and minor version numbers as two
  390. separate integers. For example, EMS 4.0 would return major
  391. version 4, minor version 0.
  392.  
  393. It's nice to know a little about the operating environment.
  394. With the below routines, you can find out what the DOS version
  395. is; what version of 4DOS, if any, is in use; and whether
  396. Microsoft Windows is running.
  397.  
  398. PROCEDURE GetDOSv (VAR MajorV, MinorV: Integer);
  399.  
  400. PROCEDURE Get4DOSv (VAR MajorV, MinorV: Integer);
  401.  
  402. PROCEDURE WinCheck (VAR MajorV, MinorV: Integer);
  403.  
  404. These return results as major and minor version numbers, as
  405. discussed above. The Get4DOSv and WinCheck routines return
  406. zeroes if 4DOS and Windows, respectively, are not in use.
  407.  
  408. There are a couple of curious features of GetDOSv to keep in
  409. mind.  If the version is 10 or higher, you're running under
  410. OS/2.  DOS version 10 is actually OS/2 1.0, version 20 is OS/2
  411. 2.0, and so on. Secondly, if you're using DOS 5.0, the version
  412. reported may not be 5.0-- DOS 5.0 can be told to reply with a
  413. lower version number to allow badly written older software to
  414. run properly.
  415.  
  416. One final routine that should be of some value is the one that
  417. allows you to find out what kind of display is available.  It
  418. tells you the specific adapter and whether the display is color
  419. or monochrome.  There is one case in which it can be confused,
  420. however-- if the adapter is CGA, the display is assumed to be
  421. color, since there is no way for the computer to know any
  422. differently.  So, although this routine provides a good idea of
  423. what is available, it would be a good idea to provide an option
  424. to tell the program that a monochrome display is attached.
  425. Microsoft normally uses "/B" for this purpose, so that might be
  426. a good standard to stick with.
  427.  
  428. PROCEDURE GetDisplay (VAR Adapter: Integer; VAR Mono: Boolean);
  429.  
  430. The adapter will be one of the following:
  431.  
  432.    1     MDA                  4     EGA
  433.    2     Hercules             5     MCGA
  434.    3     CGA                  6     VGA
  435.  
  436.                      Expression Evaluator               page 10
  437.  
  438.                          Unit: ExtMath
  439.  
  440.  
  441.  
  442. The expression evaluator solves numeric equations.  It allows
  443. you to find the result of an expression contained in a string.
  444. Normal algebraic precedence is used, e.g. 4+3*5 evaluates to
  445. 19.  The usual numeric operators (*, /, +, -, ^) are supported
  446. (multiply, divide, add, subtract, and raise to a power).
  447. Negation is also supported. Parentheses can be used for
  448. overriding the default order of operations.
  449.  
  450. You may use either double asterisk ("**") or caret ("^")
  451. symbols to indicate exponentiation.
  452.  
  453. The constant PI is recognized, as are the following functions:
  454.    ABS    absolute value        INT    integer
  455.    ACOS   inverse cosine        LOG    natural log
  456.    ASIN   inverse sine          SIN    sine
  457.    ATAN   inverse tangent       SQRT   square root
  458.    COS    cosine                TAN    tangent
  459.    FRAC   fraction
  460.  
  461. Trig functions expect angles in radians.
  462.  
  463. To evaluate an expression, you pass it to the evaluator as a
  464. string.  You will get back either an error code or a real
  465. result.  See the CALC.PAS program for a working example.
  466.  
  467. PROCEDURE Evaluate (Expression: String; VAR Result: Real;
  468.                     VAR ErrCode: Integer);
  469.  
  470. An expression evaluator adds convenience to any program that
  471. needs to accept numbers.  Why make someone reach for a
  472. calculator when number crunching is what a computer does best?
  473.  
  474.                  Extensions to Pascal's Math            page 11
  475.  
  476.                         Unit: ExtMath
  477.  
  478.  
  479.  
  480. For the most part, the math routines in this library are
  481. designed to provide alternatives to the math routines that come
  482. with Pascal.  Still, Pascal's own math support is quite
  483. adequate for many purposes, so there's no sense in ignoring
  484. it.  Here are some functions which improve on Pascal's math.
  485.  
  486. { inverse cosine }
  487. FUNCTION ArcCos (Number: Real): Real;
  488.    { 1.0 >= Number >= -1.0 }
  489.  
  490. { inverse hyperbolic cosine }
  491. FUNCTION ArcCosH (Number: Real): Real;
  492.  
  493. { inverse sine }
  494. FUNCTION ArcSin (Number: Real): Real;
  495.    { 1.0 >= Number >= -1.0 }
  496.  
  497. { inverse hyperbolic sine }
  498. FUNCTION ArcSinH (Number: Real): Real;
  499.  
  500. { inverse hyperbolic tangent }
  501. FUNCTION ArcTanH (Number: Real): Real;
  502.  
  503. { ceiling: smallest integer >= specified number }
  504. FUNCTION Ceil (Number: Real): Real;
  505.  
  506. { hyperbolic cosine }
  507. FUNCTION CosH (Number: Real): Real;
  508.  
  509. { cotangent }
  510. FUNCTION Cot (Number: Real): Real;
  511.  
  512. { cosecant }
  513. FUNCTION Csc (Number: Real): Real;
  514.  
  515. { convert degrees to radians }
  516. FUNCTION Deg2Rad (Number: Real): Real;
  517.  
  518. { the constant "e" }
  519. FUNCTION e: Real;
  520.  
  521. { error function }
  522. FUNCTION Erf (Number: Real): Real;
  523.  
  524. { factorial }
  525. FUNCTION Fact (Number: Integer): Real;
  526.  
  527. { floor: largest integer <= specified number }
  528. FUNCTION Floor (Number: Real): Real;
  529.  
  530.                  Extensions to Pascal's Math            page 12
  531.  
  532.                         Unit: ExtMath
  533.  
  534.  
  535.  
  536. { log (base 10) }
  537. FUNCTION Log (Number: Real): Real;
  538.  
  539. { convert radians to degrees }
  540. FUNCTION Rad2Deg (Number: Real): Real;
  541.  
  542. { raise a number to a power }
  543. FUNCTION Raise (Number: Real; Power: Integer): Real;
  544.  
  545. { secant }
  546. FUNCTION Sec (Number: Real): Real;
  547.  
  548. { hyperbolic sine }
  549. FUNCTION SinH (Number: Real): Real;
  550.  
  551. { tangent }
  552. FUNCTION Tan (Number: Real): Real;
  553.  
  554. { hyperbolic tangent }
  555. FUNCTION TanH (Number: Real): Real;
  556.  
  557.                        Keyboard Control                 page 13
  558.  
  559.                         Unit: Keyboard
  560.  
  561.  
  562.  
  563. The keyboard is not a particularly exciting or glamorous
  564. device.  In fact, we tend to forget about it except when it
  565. gets in the way.  Sometimes it's a hardware problem-- squishy
  566. or clacking keys, or perhaps a commonly-used key placed in an
  567. out-of-the-way location.  Then again, sometimes it's the
  568. software that's the problem.  There are many aspects of
  569. keyboard control, not all of which are necessarily related to
  570. input.  This unit will let you handle the keyboard in ways you
  571. may not have realized were possible.  Better yet, it can help
  572. make keyboard control easier than the users of your programs
  573. dreamed possible.
  574.  
  575. Let's start out with keyboard output.  Yep, not input--
  576. output.  We can stuff up to 15 keys into the keyboard buffer.
  577. Why would we ever want to do this? Perhaps to allow your
  578. program to pop-up a TSR automatically, to start another program
  579. after your program ends, or for creating key macros.  You can
  580. enter extended key codes (like function keys) by using CHR$(0)
  581. before the scan code.
  582.  
  583. PROCEDURE TypeIn (Keys: String);
  584.  
  585. The usual keyboard action is quite sluggish.  We can make it a
  586. lot crisper by changing the key repeat rate and the delay
  587. before repeating.  This will work on ATs, but not PC/XT systems.
  588.  
  589. PROCEDURE SpeedKey (RepDelay, RepRate: Integer);
  590.  
  591. The delay may be 0-3 (1 by default):
  592.  
  593.    0      250 milliseconds
  594.    1      500 milliseconds
  595.    2      750 milliseconds
  596.    3        1 second
  597.  
  598. The repeat rate may be 0-31 (11 by default).  The larger the
  599. number, the slower the speed-- 0 is around 30 cps, and 31 is
  600. around 2 cps.
  601.  
  602. I generally prefer to have the keyboard cranked up to full
  603. speed, using RepDelay and RepRate both set to zero.  This may
  604. be a bit too zippy for some people.  Experiment with it to see
  605. what you like best.
  606.  
  607. Of course, there may be reasons to make keyboard repeat less
  608. sensitive instead!  That might be a good idea in programs
  609. written for small children, for example.  You can adjust the
  610. keyboard equally well in either direction.
  611.  
  612.                        Keyboard Control                 page 14
  613.  
  614.                         Unit: Keyboard
  615.  
  616.  
  617.  
  618. Pascal allows you to control one of the keys which can
  619. interrupt your program, namely the Break key.  There's another
  620. dangerous key which PasWiz allows you to control-- the PrtSc
  621. (PrintScreen) key.  PrtSc may not seem like a hazard at first
  622. glance, but if it's pressed by accident with no printer ready,
  623. or in a graphics mode which PrtSc doesn't understand how to
  624. print, the results can be pretty messy.  So, we let you turn it
  625. off or on:
  626.  
  627. PROCEDURE SetPrtSc (PrtScON: Boolean);
  628.  
  629. Use FALSE to turn it off or TRUE to turn it back on.  If you
  630. turn off PrtSc, you MUST remember to turn it back on again
  631. before your program ends! Otherwise, an interrupt vector will
  632. point into nowhere, causing probable chaos the next time PrtSc
  633. is pressed.
  634.  
  635. Regardless of whether you've turned the PrtSc key off, you can
  636. print the screen yourself just as if PrtSc had been pressed:
  637.  
  638. PROCEDURE PrintScreen;
  639.  
  640. Now here's a strange one for you.  When IBM brought out the
  641. 101-key keyboard, called the "enhanced" keyboard, they did
  642. something bizarre to the BIOS.  They still allowed old keyboard
  643. calls to work, but they filtered out the new key codes so no
  644. one would see them.  This made sure that no one would be able
  645. to use the capabilities of the "enhanced" keyboard without
  646. rewriting their programs.  So, the keyboard has been around for
  647. years, and there are still few programs that even notice when
  648. you press F11.  Pascal does not support the enhanced keyboard
  649. at all.  Fortunately, PasWiz -does-.  You can find out if an
  650. enhanced keyboard is installed with the EnhKbd function, which
  651. is in the Equipment unit.
  652.  
  653. If there is an enhanced keyboard installed, you can activate it
  654. with this:
  655.  
  656. PROCEDURE SetEnhKbd (Enhanced: Boolean);
  657.  
  658. With enhanced keyboard support activated, all key requests that
  659. used the old services are translated to the new services.  So,
  660. SetEnhKbd affects the ReadKey (in the CRT unit that comes with
  661. Pascal) and other Pascal functions as well as other PasWiz
  662. keyboard routines.  Note that you MUST deactivate enhanced
  663. keyboard support before ending your program. Otherwise, an
  664. interrupt vector will point into nowhere, probably causing a
  665. crash on the next keypress!
  666.  
  667.                        Keyboard Control                 page 15
  668.  
  669.                         Unit: Keyboard
  670.  
  671.  
  672.  
  673. If you're about to request important input, you may not want to
  674. chance having it answered from results of the keyboard buffer--
  675. could be that the user meant those keys for another purpose.
  676. In that case, it's a good approach to clear out the keyboard
  677. buffer just before the input:
  678.  
  679. PROCEDURE ClearKbd;
  680.  
  681. No keyboard unit would be complete without a selection of
  682. routines to check the shift states and get or set the keyboard
  683. toggles.  Let's start with the toggles, which are so called
  684. because they get toggled from one state to another:
  685.  
  686. FUNCTION CapsOn: Boolean;         { Caps Lock }
  687.  
  688. FUNCTION InsertOn: Boolean;       { Insert }
  689.  
  690. FUNCTION NumOn: Boolean;          { Num Lock }
  691.  
  692. FUNCTION ScrollOn: Boolean;       { Scroll Lock }
  693.  
  694. You can also turn the toggles off or on.  It's courteous to
  695. restore the original toggle states once you end your program,
  696. so you might want to save the original values for that
  697. purpose.  Then again, I guess that doesn't apply if your
  698. program is designed for the specific purpose of setting the
  699. toggles!
  700.  
  701. PROCEDURE SetCaps (CapsLock: Boolean);        { Caps Lock }
  702.  
  703. PROCEDURE SetInsert (InsertKey: Boolean);     { Insert }
  704.  
  705. PROCEDURE SetNum (NumLock: Boolean);          { Num Lock }
  706.  
  707. PROCEDURE SetScroll (ScrollLock: Boolean);    { Scroll Lock }
  708.  
  709. Does anyone actually use ScrollLock for anything?  Just
  710. curious...
  711.  
  712.                        Keyboard Control                 page 16
  713.  
  714.                         Unit: Keyboard
  715.  
  716.  
  717.  
  718. The shift keys are unique in many respects.  They don't return
  719. codes that can be detected with ReadKey or stuffed into the
  720. keyboard buffer; several can be pressed at the same time; and
  721. they don't repeat.  You can detect 'em with PasWiz, at any rate:
  722.  
  723. FUNCTION AltPress: Boolean;         { any ALT }
  724.  
  725. FUNCTION CtrlPress: Boolean;        { any CTRL }
  726.  
  727. FUNCTION ShiftPress: Boolean;       { any SHIFT }
  728.  
  729. FUNCTION LAltPress: Boolean;        { left ALT }
  730.  
  731. FUNCTION LCtrlPress: Boolean;       { left CTRL }
  732.  
  733. FUNCTION LShiftPress: Boolean;      { left SHIFT }
  734.  
  735. FUNCTION RAltPress: Boolean;        { right ALT }
  736.  
  737. FUNCTION RCtrlPress: Boolean;       { right CTRL }
  738.  
  739. FUNCTION RShiftPress: Boolean;      { right SHIFT }
  740.  
  741. NOTE that LAltPress, LCtrlPress, RAltPress, and RCtrlPress are
  742. ONLY available for enhanced keyboards.  They will not return
  743. useful results on older keyboards.
  744.  
  745.                          String Stuff                   page 17
  746.  
  747.                          Unit: Strings
  748.  
  749.  
  750.  
  751. Strings have always been something of an afterthought in
  752. Pascal.  This unit brings in the heavy artillery!  The PasWiz
  753. string routines may be divided into the following categories:
  754. comparison, compression, encryption, extraction, searching, and
  755. miscellaneous (mostly alteration).  Let's take up these
  756. categories one at a time.
  757.  
  758. The compression routines are designed to work with ordinary
  759. text strings. The strings may not contain IBM extended-ASCII
  760. codes (CHR($80)-CHR($FF)), as these are used in the
  761. compression.  Compression works on spaces, which will give you
  762. an average of 15% compression on normal text.  If you compress
  763. printable text (i.e., no control codes), you'll get printable
  764. text in return, which makes these routines handy for use with
  765. text files.  Compression and decompression is done at an
  766. extreme rate of speed and will not affect the timing of your
  767. program in any noticeable fashion.
  768.  
  769. FUNCTION Bsq (St: String): String;     { compress a string }
  770.  
  771. FUNCTION BUsq (St: String): String;    { uncompress a string }
  772.  
  773. Comparing two strings is easy enough in Pascal, but not as
  774. flexible as might be desired for some applications.  You can
  775. tell if two strings match exactly, but not if they're
  776. reasonably close matches.  PasWiz has two fuzzy comparison
  777. routines which can help.
  778.  
  779. The Soundex routine uses a long-established algorithm to
  780. convert a word into a code which represents the sound of the
  781. word.  It is fast and can work well under properly defined
  782. circumstances; for instance, it will tell you that "Smith"
  783. sounds just like "Smythe", but not like "Banks".  Between the
  784. need for speed and the vagaries of the English language,
  785. however, you may find matches which don't work as well.
  786. Soundex is certain that "Knight" sounds just like "Smashed",
  787. for example.  So, it may be perfect for something like a phone
  788. book, but not for a spelling checker!
  789.  
  790. FUNCTION Soundex (St: String): String;
  791.  
  792. The Bickel routine, on the other hand, tells you how closely
  793. two words match. This is a relative measure, not an absolute
  794. measure, so you'd probably want to search through an entire
  795. dictionary and just keep the words which matched best.  The
  796. Bickel algorithm is slower than Soundex but is much more
  797. precise.
  798.  
  799. FUNCTION Bickel (St1, St2: String): Integer;
  800.  
  801.                          String Stuff                   page 18
  802.  
  803.                          Unit: Strings
  804.  
  805.  
  806.  
  807. There are many cases in which you might want to keep data
  808. private.  The PasWiz encryption routines provide a simple and
  809. extremely fast method for password-protecting text.  The
  810. encryption technique is trivial and will not withstand any
  811. concerted attack, but should suffice for casual use.  It will
  812. help if you pick a longish password of unusual characters, for
  813. example '[^.mE@@&o}' (don't use this example itself, please)!
  814.  
  815. There are two encryption routines (which also work as
  816. decryption routines). The first is designed to produce
  817. printable, if bizarre-looking, results which are suited for use
  818. with text files.  Text to be encrypted by this routine may not
  819. include IBM extended-ASCII characters (CHR($80) - CHR($FF)),
  820. since these are used to insure printable text.
  821.  
  822. FUNCTION CipherP (St, Passwd: String): String;
  823.  
  824. The other routine will work with any sort of text, but is not
  825. guaranteed to produce printable results.  So, it's not suited
  826. for use with text files.
  827.  
  828. FUNCTION Cipher (St, Passwd: String): String;
  829.  
  830. Of the extraction routines, two are merely convenient
  831. rephrasings of the Copy function which allow you to grab a
  832. substring from the left or right side of a string:
  833.  
  834. FUNCTION Left (St: String; Len: Integer): String;
  835.  
  836. FUNCTION Right (St: String; Len: Integer): String;
  837.  
  838. Another extraction routine is more interesting.  It allows you
  839. to extract a substring from a string which contains delimited
  840. information.  For instance, consider the following name and
  841. address string.  It has three fields, each separated by an
  842. asterisk.  We can use Extract to grab any individual field:
  843.  
  844. St := 'Tom Hanlin*3544 E. Southern Ave. #104*Mesa, AZ 85204';
  845. FOR PrtAddress := 1 TO 3 DO BEGIN
  846.    AddressLine := Extract(St, '*', PrtAddress);
  847.    WriteLn(AddressLine);
  848. END;
  849.  
  850. The extract function is defined as follows:
  851.  
  852. FUNCTION Extract (St, Delimiter: String;
  853.                   Index: Integer): String;
  854.  
  855. If you try to extract a field which doesn't exist, a null
  856. string will be returned.  Field delimiters may be anything at
  857. all, by the way-- one possible use for Extract might be to
  858. block-read a text file, splitting it apart in memory by using
  859. the carriage return and linefeed as a delimiter.
  860.  
  861.                        String Stuff                     page 19
  862.  
  863.                        Unit: Strings
  864.  
  865.  
  866.  
  867. PasWiz provides an assortment of string search routines.  One
  868. is a simple modification of Pos which allows you to start the
  869. search at a given place in the string:
  870.  
  871. FUNCTION Instr (Start: Integer; SubSt, St: String): Integer;
  872.  
  873. Another works like Pos, but returns the last match rather than
  874. the first match:
  875.  
  876. FUNCTION RPos (SubSt, St: String): Integer;
  877.  
  878. Of course, you don't always want to search for something in
  879. specific.  You might be more interested in finding the first
  880. character that fits into a given category or categories, like
  881. perhaps numbers or letters.  No problem:
  882.  
  883. FUNCTION TypePos (ChType: Integer; St: String): Integer;
  884.  
  885. The ChType value is formed by adding the numbers which
  886. represent the desired categories.  This can also be used to
  887. search for the first character which is not of a given type,
  888. since the categories are exclusive:
  889.  
  890.     1    alphabetic
  891.     2    numeric
  892.     4    symbols
  893.     8    control codes (ASCII 0-31, 127)
  894.    16    graphics codes (ASCII 128-255)
  895.    32    space (ASCII 32)
  896.  
  897. That covers the string routines which can be readily
  898. categorized.  Most of the remaining routines are designed to
  899. alter a string in one way or another. This includes being able
  900. to remove selected characters, substrings, types of characters,
  901. or repeated characters from a string; trimming the left or
  902. right side of a string of blanks; converting to uppercase,
  903. lowercase, or using the correct capitalization for a proper
  904. name; replacing one substring with another; reversing a string;
  905. and forming a new string by repeating a given substring.
  906.  
  907. The "case", "trim", and "reverse" functions are pretty much
  908. self-explanatory:
  909.  
  910. FUNCTION LowerCase (St: String): String;    { lowercase }
  911.  
  912. FUNCTION NameCase (St: String): String;     { name case }
  913.  
  914. FUNCTION UpperCase (St: String): String;    { upper case }
  915.  
  916. FUNCTION LTrim (St: String): String;        { left trim }
  917.  
  918. FUNCTION RTrim (St: String): String;        { right trim }
  919.  
  920. FUNCTION Reverse (St: String): String;      { reverse }
  921.  
  922.                        String Stuff                     page 20
  923.  
  924.                        Unit: Strings
  925.  
  926.  
  927.  
  928. The Crunch function removes adjacent repetitions of a
  929. substring.  This is particularly handy for parsing user input,
  930. for example-- you can use it to remove repeated spaces between
  931. options, etc.
  932.  
  933. FUNCTION Crunch (SubSt, St: String): String;
  934.  
  935. The Dupe function forms a string by repeating a substring.
  936. It's handy when you need a string of a given number of spaces,
  937. zeroes, or nulls.  It can also be used for drawing horizontal
  938. lines and other applications.
  939.  
  940. FUNCTION Dupe (Count: Integer; SubSt: String): String;
  941.  
  942. There are many times when it's nice to be able to replace all
  943. occurrences of one substring with another.  PasWiz can do that,
  944. no problem.  You don't have to worry about recursion, either--
  945. each occurrence is replaced only once, even if the replacement
  946. substring contains the target substring.
  947.  
  948. FUNCTION Replace (OldSubSt, NewSubSt, St: String): String;
  949.  
  950. Of course, you can delete a substring by replacing it with a
  951. null string. It's faster to use the routine designed for that
  952. purpose, though:
  953.  
  954. FUNCTION StripSt (SubSt, St: String): String;
  955.  
  956. Another routine allows you delete specified characters from a
  957. string:
  958.  
  959. FUNCTION StripCh (ChList, St: String): String;
  960.  
  961. And, last but not least, a routine which deletes specified
  962. types of characters from a string!  This can be very good for
  963. screening user input.
  964.  
  965. FUNCTION StripType (ChType: Integer; St: String): String;
  966.  
  967. The ChType value is formed by adding the numbers which
  968. represent the desired categories:
  969.  
  970.     1    alphabetic
  971.     2    numeric
  972.     4    symbols
  973.     8    control codes (ASCII 0-31, 127)
  974.    16    graphics codes (ASCII 128-255)
  975.    32    space (ASCII 32)
  976.  
  977.                             Music                       page 21
  978.  
  979.                          Unit: Music
  980.  
  981.  
  982.  
  983. Granted, the PC has never been known for its wonderful sound
  984. capabilities. Still, it has more potential than you might
  985. guess, especially given the utterly minimal Sound/Delay/NoSound
  986. routines that are provided with Pascal. The Music unit makes it
  987. much easier to use sounds by providing an actual music
  988. language.  The BACHINV and ENTERTNR demo programs demonstrate
  989. some of the possibilities.
  990.  
  991. The PasWiz music language is nearly identical to that offered
  992. by the BASIC PLAY statement.  The major difference is that the
  993. "MB" command (play the music as a background task) is not
  994. supported.  I'll add that later, if I get enough requests.
  995.  
  996. There are only two music procedures:
  997.  
  998. PROCEDURE ResetMF;
  999.  
  1000. PROCEDURE PlayMF(Sounds: String);
  1001.  
  1002. The ResetMF procedure is used to reset all music parameters to
  1003. the default values.  It would typically be used after finishing
  1004. a song to restore the music handler for the next song.
  1005.  
  1006. The PlayMF procedure is the one that does the real work.
  1007. Here's a list of the music commands supported:
  1008.  
  1009.    MB  play music as a background task (ignored)
  1010.    MF  play music as a foreground task (ignored)
  1011.    ML  legato (8/8 note length)
  1012.    MN  normal music (7/8 note length)
  1013.    MN  staccato (6/8 note length)
  1014.    Ln  Length of notes (n = 1-64; note length = 1/n)
  1015.    Nn  Note number (n = 0-84; 0 is a rest)
  1016.    On  Octave (n = 0-6, default 4)
  1017.    Pn  Pause (n = 1-64; pause length = 1/n)
  1018.    Tn  Tempo (n = 32-255, default 120; quarter notes/minute)
  1019.    <   move up an octave (max 6)
  1020.    >   move down an octave (min 0)
  1021.  
  1022. You can also use the actual letters of the notes (C, D, E, F,
  1023. G, A, and B). If you're not particularly musical, these
  1024. correspond to "do, re, mi, fa, so, la, ti" (with the final "do"
  1025. being C again, but an octave higher).  To play a scale, you'd
  1026. use 'CDEFGAB>C'.  The notes may be followed by dots, by note
  1027. lengths, and by sharp or flat symbols (a '+' or '#' for a
  1028. sharp, a '-' for a flat).  For example, 'D-.' is a dotted D
  1029. flat.  The dot means that the note will play for half again its
  1030. usual length.  Dots can be repeated.
  1031.  
  1032. I might note (ahem) that the so-called "ANSI" music offered by
  1033. some BBSes and comm programs is based on this same music
  1034. language.  If you're writing telecomm software, this unit makes
  1035. it trivial to add sound.
  1036.  
  1037.                             Mouse                       page 22
  1038.  
  1039.                          Unit: Mouse
  1040.  
  1041.  
  1042.  
  1043. Considering the ubiquity of the mouse these days, it's a marvel
  1044. to me that none of the popular programming languages provides
  1045. any support for it.  Well, BASIC supports it via light pen
  1046. emulation, but that scarcely counts.  Anyway, this is a simple
  1047. little unit which provides you direct access to the mouse
  1048. driver.  It will work with any Microsoft-compatible mouse
  1049. driver.
  1050.  
  1051. A few words are necessary on mouse handling.  To begin with,
  1052. the best time to check for a mouse is immediately after you've
  1053. established the desired video mode.  The mouse driver
  1054. initializes certain information when you check for it, so it's
  1055. a good idea to check for it only once, at the appropriate time.
  1056.  
  1057. The mouse cursor was implemented in a rather bizarre manner.
  1058. If you call ShowCursor, you're guaranteed that the mouse cursor
  1059. will be visible; however, this also increments an internal
  1060. visibility flag.  If you call ShowCursor multiple times, you
  1061. will also have to call HideCursor multiple times before the
  1062. dang cursor actually disappears.
  1063.  
  1064. The mouse driver was apparently implemented without any thought
  1065. for the future.  In text mode, it returns coordinates based on
  1066. CGA hi-res graphics mode-- 640x200 instead of the expected
  1067. 80x25.  If you use the mouse driver in text mode, you'll have
  1068. to compensate for this (divide coordinates by 8 to convert to
  1069. text mode, or multiply by 8 to convert to the mouse virtual
  1070. mode). The CGA low-res 320x200 graphics mode is implemented
  1071. likewise.  It seems Microsoft thought that 640x200 would be the
  1072. ultimate resolution, so they translated everything to a 640x200
  1073. virtual mode.  Arrgh.  Fortunately, this does not apply to
  1074. video modes other than text and CGA graphics.
  1075.  
  1076. I understand that it's possible to get the mouse working in
  1077. Hercules graphics mode, but I'm not sure what the details are.
  1078. If anyone out there knows, please let me know, and I'll pass it
  1079. along.
  1080.  
  1081. Since Microsoft was initially very tight-lipped about the mouse
  1082. functions, older mouse drivers for Microsoft-compatible rodents
  1083. don't necessarily have all the functions available (this
  1084. includes Logitech, amazingly enough).  The Microsoft mouse
  1085. driver continues to be updated in a rapid and haphazard manner,
  1086. so keeping up-to-date is no guarantee.  However, if you have
  1087. any problems with these routines, you can almost certainly
  1088. clear them up by getting a newer mouse driver.  The routines in
  1089. this unit are almost all old, well-established functions.
  1090. "Iffy" ones are marked for your convenience.
  1091.  
  1092.                             Mouse                       page 23
  1093.  
  1094.                          Unit: Mouse
  1095.  
  1096.  
  1097.  
  1098. The first function to consider simply tells you whether a mouse
  1099. is available, and if so, how many buttons it has.  It also
  1100. resets the mouse driver, so it should be used only at the
  1101. beginning of your program (or after changing the video mode).
  1102.  
  1103. FUNCTION Init: Integer;
  1104.    { returns 0 if no mouse, else # of buttons }
  1105.  
  1106. Most often, you'll want to know which mouse button(s) are
  1107. pressed and where the mouse cursor is:
  1108.  
  1109. FUNCTION LeftButton: Boolean;
  1110.    { TRUE if pressed }
  1111.  
  1112. FUNCTION MidButton: Boolean;
  1113.    { always FALSE on 2-button rodents }
  1114.  
  1115. FUNCTION RightButton: Boolean;
  1116.    { TRUE if pressed }
  1117.  
  1118. FUNCTION WhereX: Integer;
  1119.    { X-coord (see notes on previous page) }
  1120.  
  1121. FUNCTION WhereY: Integer;
  1122.    { Y-coord (see notes on previous page) }
  1123.  
  1124. As well as finding the current mouse information, it's possible
  1125. to find out what the mouse has been doing since you last
  1126. checked.  Two sets of routines exist: one to find out how many
  1127. times a button was pressed and where it was at the last press,
  1128. and one to find out how many times a button was released and
  1129. where it was at the last release.
  1130.  
  1131. PROCEDURE LeftClick(VAR Count, X, Y: Integer);
  1132.  
  1133. PROCEDURE MidClick(VAR Count, X, Y: Integer);
  1134.  
  1135. PROCEDURE RightClick(VAR Count, X, Y: Integer);
  1136.  
  1137. PROCEDURE LeftRelease(VAR Count, X, Y: Integer);
  1138.  
  1139. PROCEDURE MidRelease(VAR Count, X, Y: Integer);
  1140.  
  1141. PROCEDURE RightRelease(VAR Count, X, Y: Integer);
  1142.  
  1143.                             Mouse                       page 24
  1144.  
  1145.                          Unit: Mouse
  1146.  
  1147.  
  1148.  
  1149. There's one more informational routine.  It tells you the basic
  1150. mouse software and hardware stats: driver version, connector
  1151. type (serial, bus, etc), and IRQ used.  This routine is
  1152. slightly hazardous in that, although Microsoft claims it has
  1153. existed from the first, other manufacturers (including
  1154. Logitech) have taken some time to implement it.  In other
  1155. words, it may not return useful information.  The routine
  1156. conducts a self-check and will return all zeroes if it suspects
  1157. the information is not good, but even so... proceed with care.
  1158.  
  1159. PROCEDURE Info(VAR Version: Real; VAR Connector, IRQ: Byte);
  1160.  
  1161. Connector info: 1=bus, 2=serial, 3=InPort, 4=PS/2,
  1162. 5=Hewlett-Packard IRQs: 0=PS/2; 2-5, 7 are actual IRQ numbers.
  1163. It is conceivable that higher IRQ numbers may be supported on
  1164. AT-type machines, though not by Microsoft.
  1165.  
  1166. Of course, you can set mouse info as well as retrieving it.
  1167. The following routines are pretty well self-explanatory (don't
  1168. forget the notes about the strange text-mode and CGA coordinate
  1169. handling, and cursor handling):
  1170.  
  1171. { hide the mouse cursor }
  1172. PROCEDURE HideCursor;
  1173.  
  1174. { (maybe) make the cursor visible }
  1175. PROCEDURE ShowCursor;
  1176.  
  1177. { set the cursor position }
  1178. PROCEDURE GotoXY(X, Y: Integer);
  1179.  
  1180. { set the cursor range }
  1181. PROCEDURE Window(X1, Y1, X2, Y2: Integer);
  1182.  
  1183. There are other possibilities supported by the mouse driver
  1184. that I have not implemented here.  They're mostly on the rather
  1185. esoteric side and are not supported by anything except recent
  1186. Microsoft mouse drivers and perhaps some close compatibles,
  1187. such as Logitech.
  1188.  
  1189. Among the mouse capabilities I haven't implemented are finding
  1190. out how fast and in what direction the mouse is moving, the
  1191. coordinate size of the screen as far as the mouse is concerned,
  1192. finding out the video modes that the mouse driver understands,
  1193. setting mouse speed and sensitivity parameters, setting up an
  1194. interrupt-driven system for handling mouse events, and a few
  1195. others.
  1196.  
  1197.                             Mouse                       page 25
  1198.  
  1199.                          Unit: Mouse
  1200.  
  1201.  
  1202.  
  1203. None of these missing capabilities is particularly vital (or
  1204. even useful) for the average mouse application.  However, if
  1205. you're interested in any of these capabilities, let me know
  1206. which ones, and I'll be glad to add them to PasWiz.
  1207.  
  1208. Note: if you're confused at how I can get away with duplicating
  1209. the names of existing procedures... well, it's easy enough.
  1210. Let's consider WhereX.  It means one thing to Pascal's Crt unit
  1211. and another to the PasWiz Mouse unit. Since the Mouse unit
  1212. doesn't use the Crt unit, it has no problem with any
  1213. ambiguity.  Existing programs that don't use the Mouse unit
  1214. will likewise have no problems, since they don't know about the
  1215. new routine.  Suppose you want to use both the Crt and Mouse
  1216. units together, however?  There's the rub!
  1217.  
  1218. You can specify a routine from a given unit by including the
  1219. unit name when you use the routine.  For instance:
  1220.  
  1221. X := Mouse.WhereX;      { get the mouse cursor position }
  1222.  
  1223. X := Crt.WhereX;        { get the normal cursor position }
  1224.  
  1225. This allows multiple units to use the same names for things.
  1226. While this may seem like a bit of a pain, since you have to
  1227. specify which you want, it has a major built-in advantage if
  1228. used properly.  What's properly?  When a routine in one unit
  1229. works just like a routine by the same name in another unit.
  1230. When I call the mouse routine "WhereX", for instance, I've also
  1231. told you what it is for and how to use it.  So, the name itself
  1232. contains a lot of useful information on how to use the
  1233. routine!  That's what I call a major advantage.
  1234.  
  1235.