commit a2139c12eab6d925b75233dc19bc6481c0641d95 Author: umjammer Date: Tue Aug 23 08:39:34 2011 +0000 diff --git a/appleii.txt b/appleii.txt new file mode 100644 index 0000000..a04e711 --- /dev/null +++ b/appleii.txt @@ -0,0 +1,118 @@ + +---- BD-J AppleII Emulator ---- + +Copyright (c) 2008 by umjammer +http://vavivavi.blogspot.com/ + +* ORIGINAL + + AppleIIGo + + http://www-personal.umich.edu/~mressl/appleiigo/ + +* LISENCE + + GPL (AppleIIGo is GPL) + +* TODO + + .gz reader (why doesn't work???) + virtual keyboard (details) + +* DONE + + improve pad control + disk selection mode + virtual keyboard + .nib reader + +* INSTALL + + 1. unpack bdjappleii-x.xx.rar + + 2. copy AVCHD directory into + + (SD Card) /PRIVATE directory + (Memory Stick) / (ROOT) directory + (other USBz) i don't know... maybe / (ROOT) directory + + 3. copy APPLE2E.ROM into .../AVCHD directory + + 4. copy your .dsk image into .../AVCHD directory + + 5. modify .../AVCHD/appleii.properties + + diskDrive1=your .dsk or .nib image + + 6. select AVCHD on your PS3 XMB Video Menu + +* USAGE (SIXAXIS) + + 1. first you are in NORMAL MODE. + + CIRCLE Right Pad Button + SQUARE Left Pad Button + UP Pad Up + DOWN Pad Down + LEFT Pad Left + RIGHT Pad Right + BLUE Button Goto VIRTUAL KEYBORD MODE + GREEN Button Restart + YELLOW Button Reset + + 2. VIRTUAL KEYBORD MODE + + CIRCLE Push selected key + UP Key selection Up + DOWN Key selection Down + LEFT Key selection Left + RIGHT Key selection Right + BLUE Button Goto DISK DRIVE 1 MODE + GREEN Button Restart + + 3. DISK DRIVE 1 MODE + + CIRCLE Select disk image + SQUARE Release disk image + UP Previous disk image + DOWN Next disk image + BLUE Button Goto DISK DRIVE 2 MODE + GREEN Button Restart + + 4. DISK DRIVE 2 MODE + + CIRCLE Select disk image + SQUARE Release disk image + UP Previous disk image + DOWN Next disk image + BLUE Button Goto NORMAL MODE + GREEN Button Restart + +* ROMz + + http://apple2.org.za/gswv/a2zine/System/ + ftp://ftp.apple.asimov.net/pub/apple_II/ + +* GAMEz + + http://www.virtualapple.org/ + +* HISTORY + +0.12 09-Oct-2008 + + improve pad control (i fogot keyReleased() method calling at base ;-P) + +0.11 28-Sep-2008 + + source code more MVC separation + +0.10 26-Sep-2008 + + virtual keyboard + add disk selection mode + .nib reader + +0.00 15-Sep-2008 + + initial version diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..bfc92b1 --- /dev/null +++ b/build.xml @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/etc/bdjo.xml b/etc/bdjo.xml new file mode 100644 index 0000000..90db051 --- /dev/null +++ b/etc/bdjo.xml @@ -0,0 +1,43 @@ + + + + + *.* + 00000 + 1 + + + + + + 00000 + TITLE_BOUND_DISC_BOUND + /00000 + 0x0 + + vavi.apps.appleii.AppleIIApp + 1 + + 1 + 0 + 0 + 1 + + V_11 + + 0x4000 + 0x1 + 0x56789abc + 0x1 + + + . + 0xffe00000 + + 00000 + QHD_960_540 + false + false + + V_0200 + diff --git a/etc/bluray.MyXlet.perm b/etc/bluray.MyXlet.perm new file mode 100644 index 0000000..b225fb3 --- /dev/null +++ b/etc/bluray.MyXlet.perm @@ -0,0 +1,12 @@ + + + + + + + + + * + + + \ No newline at end of file diff --git a/etc/config/settings.txt b/etc/config/settings.txt new file mode 100644 index 0000000..42e42d9 --- /dev/null +++ b/etc/config/settings.txt @@ -0,0 +1,28 @@ +#Mind that paths can not contain backslash +#Make sure there are no spaces after the values + +console.font=Helvetica +console.fontsize=10 +console.height=200 +console.show=true +console.width=500 +console.x=0 +console.y=0 +extra.classpath= +file.applications=config/applications.xml +file.defaultbg=config/defaultbg.jpg +file.settings=config/settings.txt +font.sizeoffset=-2 +path.config=config +remote.show=true +safearea.color=#ffee00 +safearea.height=556 +safearea.show=true +safearea.width=700 +safearea.x=10 +safearea.y=10 +tv.center=true +tv.screenheight=576 +tv.screenwidth=720 +tv.x=0 +tv.y=0 diff --git a/etc/gpl-2.0.txt b/etc/gpl-2.0.txt new file mode 100644 index 0000000..d511905 --- /dev/null +++ b/etc/gpl-2.0.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/src/main/java/vavi/apps/appleii/AppleDisplay.java b/src/main/java/vavi/apps/appleii/AppleDisplay.java new file mode 100644 index 0000000..b2d2e16 --- /dev/null +++ b/src/main/java/vavi/apps/appleii/AppleDisplay.java @@ -0,0 +1,1046 @@ +/* + * AppleIIGo + * Display processing + * (C) 2006 by Marc S. Ressl (ressl@lonetree.com) + * Released under the GPL + */ + +package vavi.apps.appleii; + + +/** + * AppleDisplay class

+ * Refreshes the display + */ +public class AppleDisplay implements Runnable { + // Instances of other classes + private EmAppleII apple; + + // Configuration variables + public static final int COLORMODE_GREEN = 0; + public static final int COLORMODE_COLOR = 1; + + private int colorMode; + + // Refresh + private int refreshRate; + private long refreshInterval; + private long refreshDelayCumulative; + private long refreshDelayPerSecond; + private long refreshCycle; + + private boolean isPrecalcRequested = true; + private boolean isRefreshRequested = true; + + // Graphics interface variables + private boolean[] graphicsDirty = new boolean[0x6000 >> 7]; + private int graphicsMode; + + // Display + private static final int DISPLAY_CHAR_SIZE_X = 7; + private static final int DISPLAY_CHAR_SIZE_Y = 8; + private static final int DISPLAY_CHAR_COUNT_X = 80; + private static final int DISPLAY_CHAR_COUNT_Y = 24; + public static final int DISPLAY_SIZE_X = DISPLAY_CHAR_COUNT_X * DISPLAY_CHAR_SIZE_X; + public static final int DISPLAY_SIZE_Y = DISPLAY_CHAR_COUNT_Y * DISPLAY_CHAR_SIZE_Y; + + // Display composition + private int[] displayImageBuffer; + + public int[] getDisplayImageBuffer() { + return displayImageBuffer; + } + + // Display scale + private float displayScale; + + // Display palette + private int[] displayPalette; + private static final int[] displayPaletteGreen = { + 0xff000000, 0xff0e470e, 0xff041204, 0xff166e16, + 0xff0f4a0f, 0xff115411, 0xff0c3b0c, 0xff1f9e1f, + 0xff125c12, 0xff1b8a1b, 0xff22ab22, 0xff24b524, + 0xff1A871a, 0xff2de32d, 0xff25bd25, 0xff32ff32 + }; + private static final int[] displayPaletteColor = { + 0xff000000, 0xffdd0033, 0xff000099, 0xffdd22dd, + 0xff007722, 0xff555555, 0xff2222ff, 0xff66aaff, + 0xff885500, 0xffff6600, 0xffaaaaaa, 0xffff9988, + 0xff11dd00, 0xffffff00, 0xff44ff99, 0xffffffff + }; + + // Character stuff + private static final int CHARSET_CHAR_SIZE_X = 8; + private static final int CHARSET_CHAR_SIZE_Y = 8; + private static final int CHARSET_SIZE_X = 0x100 * CHARSET_CHAR_SIZE_X; + private static final int CHARSET_SIZE_Y = CHARSET_CHAR_SIZE_Y; + + private static final int CHARMAP_NORMAL = 0; + private static final int CHARMAP_FLASH = 1; + private static final int CHARMAP_ALT = 2; + + private int[] charSet = new int[CHARSET_SIZE_X * CHARSET_CHAR_SIZE_Y]; + private int[] charMap; + private int[][] charMaps = new int[3][0x100]; + private long charMapFlashCycle = 0; + private boolean isCharMapFlash = false; + + private int[][] charMapLookup = { + { 0xc0, 0xa0, 0x40, 0x20, 0x40, 0x20, 0x40, 0x60 }, + { 0xc0, 0xa0, 0xc0, 0xa0, 0x40, 0x20, 0x40, 0x60 }, + { 0xc0, 0xa0, 0x00, 0xe0, 0x40, 0x20, 0x40, 0x60 }, + }; + + private static final int[] textLineAddress = { + 0x0000, 0x0080, 0x0100, 0x0180, 0x0200, 0x0280, 0x0300, 0x0380, + 0x0028, 0x00a8, 0x0128, 0x01a8, 0x0228, 0x02a8, 0x0328, 0x03a8, + 0x0050, 0x00d0, 0x0150, 0x01d0, 0x0250, 0x02d0, 0x0350, 0x03d0, + }; + + // Hires stuff + private int hiresEvenOddToWord[] = new int[0x200]; + private int hiresWord[] = new int[8]; + private int hiresWordNext[] = new int[8]; + private int hiresLookup[] = new int[0x100]; // Bits: [NNccccPP] - Next, current, Previous bits + private static final int hiresLookupColor[] = { + // Bits: [PPNNcccc] - Previous, Next, current bits => 4 pixel @ 4 bit color output + // Color-bleeding algorithm + 0x0000, 0x0111, 0x2222, 0x2333, 0x4440, 0x4551, 0x6662, 0x6773, 0x8800, 0x8911, 0xaa22, 0xab33, 0xcc40, 0xcd51, 0xee62, 0xef73, // 00cccc00 + 0x1000, 0x1111, 0x3222, 0x3333, 0x5440, 0x5551, 0x7662, 0x7773, 0x9800, 0x9911, 0xba22, 0xbb33, 0xdc40, 0xdd51, 0xfe62, 0xff73, // 01cccc00 + 0x0000, 0x0111, 0x2222, 0x2333, 0x4440, 0x4551, 0x6662, 0x6773, 0x8800, 0x8911, 0xaa22, 0xab33, 0xcc40, 0xcd51, 0xee62, 0xef73, // 10cccc00 + 0x1000, 0x1111, 0x3222, 0x3333, 0x5440, 0x5551, 0x7662, 0x7773, 0x9800, 0x9911, 0xba22, 0xbb33, 0xdc40, 0xdd51, 0xfe62, 0xff73, // 11cccc00 + 0x0004, 0x0115, 0x2226, 0x2337, 0x4444, 0x4555, 0x6666, 0x6777, 0x8804, 0x8915, 0xaa26, 0xab37, 0xcc44, 0xcd55, 0xee66, 0xef77, // 00cccc01 + 0x1004, 0x1115, 0x3226, 0x3337, 0x5444, 0x5555, 0x7666, 0x7777, 0x9804, 0x9915, 0xba26, 0xbb37, 0xdc44, 0xdd55, 0xfe66, 0xff77, // 01cccc01 + 0x0004, 0x0115, 0x2226, 0x2337, 0x4444, 0x4555, 0x6666, 0x6777, 0x8804, 0x8915, 0xaa26, 0xab37, 0xcc44, 0xcd55, 0xee66, 0xef77, // 10cccc01 + 0x1004, 0x1115, 0x3226, 0x3337, 0x5444, 0x5555, 0x7666, 0x7777, 0x9804, 0x9915, 0xba26, 0xbb37, 0xdc44, 0xdd55, 0xfe66, 0xff77, // 11cccc01 + 0x0088, 0x0199, 0x22aa, 0x23bb, 0x44c8, 0x45d9, 0x66ea, 0x67fb, 0x8888, 0x8999, 0xaaaa, 0xabbb, 0xccc8, 0xcdd9, 0xeeea, 0xeffb, // 00cccc10 + 0x1088, 0x1199, 0x32aa, 0x33bb, 0x54c8, 0x55d9, 0x76ea, 0x77fb, 0x9888, 0x9999, 0xbaaa, 0xbbbb, 0xdcc8, 0xddd9, 0xfeea, 0xfffb, // 01cccc10 + 0x0088, 0x0199, 0x22aa, 0x23bb, 0x44c8, 0x45d9, 0x66ea, 0x67fb, 0x8888, 0x8999, 0xaaaa, 0xabbb, 0xccc8, 0xcdd9, 0xeeea, 0xeffb, // 10cccc10 + 0x1088, 0x1199, 0x32aa, 0x33bb, 0x54c8, 0x55d9, 0x76ea, 0x77fb, 0x9888, 0x9999, 0xbaaa, 0xbbbb, 0xdcc8, 0xddd9, 0xfeea, 0xfffb, // 11cccc10 + 0x008c, 0x019d, 0x22ae, 0x23bf, 0x44cc, 0x45dd, 0x66ee, 0x67ff, 0x888c, 0x899d, 0xaaae, 0xabbf, 0xcccc, 0xcddd, 0xeeee, 0xefff, // 00cccc11 + 0x108c, 0x119d, 0x32ae, 0x33bf, 0x54cc, 0x55dd, 0x76ee, 0x77ff, 0x988c, 0x999d, 0xbaae, 0xbbbf, 0xdccc, 0xdddd, 0xfeee, 0xffff, // 01cccc11 + 0x008c, 0x019d, 0x22ae, 0x23bf, 0x44cc, 0x45dd, 0x66ee, 0x67ff, 0x888c, 0x899d, 0xaaae, 0xabbf, 0xcccc, 0xcddd, 0xeeee, 0xefff, // 10cccc11 + 0x108c, 0x119d, 0x32ae, 0x33bf, 0x54cc, 0x55dd, 0x76ee, 0x77ff, 0x988c, 0x999d, 0xbaae, 0xbbbf, 0xdccc, 0xdddd, 0xfeee, 0xffff, // 11cccc11 + + // First table + 0x0000, 0x0001, 0x0020, 0x0033, 0x0400, 0x0505, 0x0660, 0x0777, 0x8000, 0x9009, 0xa0a0, 0xb0bb, 0xcc00, 0xdd0d, 0xeee0, 0xffff, // 00cccc00 + 0x0000, 0x1111, 0x0020, 0x0033, 0x0400, 0x0505, 0x0660, 0x0777, 0x8000, 0x9009, 0xa0a0, 0xb0bb, 0xcc00, 0xdd0d, 0xeee0, 0xffff, // 01cccc00 + 0x0000, 0x0001, 0x2222, 0x0033, 0x0400, 0x0505, 0x0660, 0x0777, 0x8000, 0x9009, 0xa0a0, 0xb0bb, 0xcc00, 0xdd0d, 0xeee0, 0xffff, // 10cccc00 + 0x0000, 0x0001, 0x0020, 0x3333, 0x0400, 0x0505, 0x0660, 0x0777, 0xf000, 0x9009, 0xa0a0, 0xb0bb, 0xff00, 0xdd0d, 0xfff0, 0xffff, // 11cccc00 + 0x0000, 0x0001, 0x0020, 0x0033, 0x4444, 0x0505, 0x0660, 0x0777, 0x8000, 0x9009, 0xa0a0, 0xb0bb, 0xcc00, 0xdd0d, 0xeee0, 0xffff, // 00cccc01 + 0x0000, 0x0001, 0x0020, 0x0033, 0x0400, 0x5555, 0x0660, 0x0777, 0x8000, 0x9009, 0xa0a0, 0xb0bb, 0xcc00, 0xdd0d, 0xeee0, 0xffff, // 01cccc01 + 0x0000, 0x0001, 0x0020, 0x0033, 0x0400, 0x0505, 0x6666, 0x0777, 0x8000, 0x9009, 0xa0a0, 0xb0bb, 0xcc00, 0xdd0d, 0xeee0, 0xffff, // 10cccc01 + 0x0000, 0x0001, 0x0020, 0x0033, 0x0400, 0x0505, 0x0660, 0x7777, 0x8000, 0x9009, 0xa0a0, 0xb0bb, 0xcc00, 0xdd0d, 0xeee0, 0xffff, // 11cccc01 + 0x0000, 0x0001, 0x0020, 0x0033, 0x0400, 0x0505, 0x0660, 0x0fff, 0x8888, 0x9009, 0xa0a0, 0xb0bb, 0xcc00, 0xdd0d, 0xeee0, 0xffff, // 00cccc10 + 0x0000, 0x0001, 0x0020, 0x0033, 0x0400, 0x0505, 0x0660, 0x0777, 0x8000, 0x9999, 0xa0a0, 0xb0bb, 0xcc00, 0xdd0d, 0xeee0, 0xffff, // 01cccc10 + 0x0000, 0x0001, 0x0020, 0x0033, 0x0400, 0x0505, 0x0660, 0x0777, 0x8000, 0x9009, 0xaaaa, 0xb0bb, 0xcc00, 0xdd0d, 0xeee0, 0xffff, // 10cccc10 + 0x0000, 0x0001, 0x0020, 0x0033, 0x0400, 0x0505, 0x0660, 0x0777, 0x8000, 0x9009, 0xa0a0, 0xbbbb, 0xcc00, 0xdd0d, 0xeee0, 0xffff, // 11cccc10 + 0x0000, 0x000f, 0x0020, 0x00ff, 0x0400, 0x0505, 0x0660, 0x0fff, 0x8000, 0x9009, 0xa0a0, 0xb0bb, 0xcccc, 0xdd0d, 0xeee0, 0xffff, // 00cccc11 + 0x0000, 0x0001, 0x0020, 0x0033, 0x0400, 0x0505, 0x0660, 0x0777, 0x8000, 0x9009, 0xa0a0, 0xb0bb, 0xcc00, 0xdddd, 0xeee0, 0xffff, // 01cccc11 + 0x0000, 0x0001, 0x0020, 0x0033, 0x0400, 0x0505, 0x0660, 0x0777, 0x8000, 0x9009, 0xa0a0, 0xb0bb, 0xcc00, 0xdd0d, 0xeeee, 0xffff, // 10cccc11 + 0x0000, 0x000f, 0x00f0, 0x00ff, 0x0f00, 0x0f0f, 0x0ff0, 0x0fff, 0xf000, 0xf00f, 0xf0f0, 0xf0ff, 0xff00, 0xff0f, 0xfff0, 0xffff, // 11cccc11 + }; + private int[] doubleHiresPalette; + private static final int[] doubleHiresPaletteColor = { + 0x000000, 0x000099, 0x007722, 0x2222ff, + 0x885500, 0xaaaaaa, 0x11dd00, 0x44ff99, + 0xdd0033, 0xdd22dd, 0x555555, 0x66aaff, + 0xff6600, 0xff9988, 0xffff00, 0xffffff, + }; + + // Thread stuff + private boolean isPaused = true; + private Thread thread; + + /** + * AppleDisplay class constructor + * + * @param apple The EmAppleII instance + */ + public AppleDisplay(EmAppleII apple) { + this.apple = apple; + + // Create display image + displayImageBuffer = new int[DISPLAY_SIZE_X * DISPLAY_SIZE_Y]; + + // Character maps + precalcCharMaps(); + + // Hires + precalcHiresEvenEddToWord(); + + // Set parameters + setScale(1.0f); + setRefreshRate(10); + setColorMode(COLORMODE_GREEN); + requestRefresh(); + } + + /** + * Set scale + */ + public void setScale(float value) { + if (value <= 0.0f) { + return; + } + + displayScale = value; + isPrecalcRequested = true; + } + + /** + * Get scale + */ + public float getScale() { + return displayScale; + } + + /** + * Set refresh rate + * + * @param value Display refresh rate in mHz + */ + public void setRefreshRate(int value) { + if (value <= 0.0f) { + return; + } + + this.refreshRate = value; + refreshInterval = (int) (1000.0 / value); + } + + /** + * Get refresh rate + */ + public int getRefreshRate() { + return refreshRate; + } + + /** + * Set color mode + */ + public void setColorMode(int value) { + colorMode = value; + isPrecalcRequested = true; + } + + /** + * Get color mode + */ + public int getColorMode() { + return colorMode; + } + + /** + * Set paused + */ + public void setPaused(boolean value) { + if (isPaused == value) { + return; + } + + isPaused = value; + if (isPaused) { + try { + thread.join(1000); + } catch (InterruptedException e) { + } + apple.view.repaint(); + } else { + isRefreshRequested = true; + thread = new Thread(this); + thread.start(); + } + } + + /** + * Get paused + */ + public boolean isPaused() { + return isPaused; + } + + public void requestRefresh() { + isRefreshRequested = true; + } + + /** + * Step instruction in debug mode + */ + public String getStatInfo() { + StringBuffer statInfo = new StringBuffer(); + long refreshRateCurrent; + + // Calculate effective CPU speed + if (refreshDelayPerSecond > 1000) { + refreshRateCurrent = refreshRate * 1000 / refreshDelayPerSecond; + } else { + refreshRateCurrent = refreshRate; + } + + // Return FPS + statInfo.append(" FPS=").append(refreshRateCurrent).append(" [").append(refreshDelayPerSecond).append(" ms/s]\n"); + statInfo.append(" GM=").append(graphicsMode).append("\n"); + + statInfo.append(" ").append((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1024L).append("KB/").append(Runtime.getRuntime().totalMemory() / 1024L).append("KB"); + + return statInfo.toString(); + } + + /** + * Display refresh thread + */ + public void run() { + try { + while (!isPaused) { + long refreshStart = System.currentTimeMillis(); + long refreshDelay; + + refreshDisplay(); + + refreshDelay = System.currentTimeMillis() - refreshStart; + + refreshDelayCumulative += refreshDelay; + refreshCycle++; + if (refreshCycle >= refreshRate) { + refreshDelayPerSecond = refreshDelayCumulative; + refreshDelayCumulative = refreshCycle = 0; + } + + if (refreshDelay < refreshInterval) { + Thread.sleep(refreshInterval - refreshDelay); + } + } + } catch (Throwable e) { +apple.view.debug(e); +apple.view.repaint(); + } + } + + /** + * Display refresh + */ + private void refreshDisplay() { + boolean isCharsetUpdateRequested = false; + boolean isSetDirtyRequested = false; + boolean isSetHiresDirtyRequested = false; + boolean isRenderRequested = false; + + // Precalculation + if (isPrecalcRequested) { + isPrecalcRequested = false; + precalcDisplay(); + graphicsMode = -1; + } + + // Repaint if graphics mode changes + if (graphicsMode != apple.graphicsMode) { + graphicsMode = apple.graphicsMode; + isCharsetUpdateRequested = true; + isSetHiresDirtyRequested = true; + } + + // Periodic refresh + if (charMapFlashCycle <= 0) { + charMapFlashCycle = refreshRate / 4 - 1; + isCharMapFlash = !isCharMapFlash; + isCharsetUpdateRequested = true; + } else { + charMapFlashCycle--; + } + + // Some internal variables + boolean isSomeText = ((graphicsMode & (EmAppleII.GR_TEXT | EmAppleII.GR_MIXMODE)) != 0); + boolean isSomeLores = ((graphicsMode & (EmAppleII.GR_TEXT | EmAppleII.GR_HIRES)) == 0); + boolean isSomeHires = ((graphicsMode & (EmAppleII.GR_TEXT | EmAppleII.GR_HIRES)) == EmAppleII.GR_HIRES); + + boolean isMixedMode = ((graphicsMode & (EmAppleII.GR_TEXT | EmAppleII.GR_MIXMODE)) == EmAppleII.GR_MIXMODE); + boolean isPage2 = ((graphicsMode & (EmAppleII.GR_80STORE | EmAppleII.GR_PAGE2)) == EmAppleII.GR_PAGE2); + boolean isAltChar = ((graphicsMode & EmAppleII.GR_ALTCHAR) != 0); + boolean isDoubleTextMode = ((graphicsMode & EmAppleII.GR_80CHAR) == EmAppleII.GR_80CHAR); + boolean isDoubleGraphicsMode = ((graphicsMode & (EmAppleII.GR_80CHAR | EmAppleII.GR_DHIRES)) == (EmAppleII.GR_80CHAR | EmAppleII.GR_DHIRES)); + + int baseAddressText = isPage2 ? EmAppleII.MEM_MAIN_RAM2 : EmAppleII.MEM_MAIN_TEXT; + int baseAddressHires = isPage2 ? EmAppleII.MEM_MAIN_RAM3 : EmAppleII.MEM_MAIN_HIRES; + + // Set char map + if (isCharsetUpdateRequested) { + if (isAltChar) { + setCharMap(CHARMAP_ALT); + } else if (isCharMapFlash) { + setCharMap(CHARMAP_FLASH); + } else { + setCharMap(CHARMAP_NORMAL); + } + + isSetDirtyRequested = true; + isRefreshRequested = true; + } + + // Refresh dirty buffers? + if (isSetDirtyRequested) { + if (isSomeText || isSomeLores) { + setTextBufferDirty(baseAddressText); + } + + if (isSetHiresDirtyRequested && isSomeHires) { + setHiresBufferDirty(baseAddressHires); + } + + isRenderRequested = true; + } else { + if ((isSomeText || isSomeLores) && isTextBufferDirty(baseAddressText)) { + isRenderRequested = true; + } + + if (isSomeHires && isHiresBufferDirty(baseAddressHires)) { + isRenderRequested = true; + } + } + + // Draw + if (isRenderRequested) { + if (isSomeText) { + if (isDoubleTextMode) { + renderDoubleText(baseAddressText, isMixedMode); + } else { + renderText(baseAddressText, isMixedMode); + } + } + + if (isSomeHires) { + if (isDoubleGraphicsMode) { + renderDoubleHires(baseAddressHires, isMixedMode); + } else { + renderHires(baseAddressHires, isMixedMode); + } + } else if (isSomeLores) { + if (isDoubleGraphicsMode) { + renderDoubleLores(baseAddressText, isMixedMode); + } else { + renderLores(baseAddressText, isMixedMode); + } + } + + isRefreshRequested = true; + } + + if (isRefreshRequested) { + isRefreshRequested = false; + apple.view.repaint(); + } + } + + /** + * Set text buffer dirty + */ + private void setTextBufferDirty(int baseAddress) { + // Update dirty + int addressStart = baseAddress >> 7; + int addressEnd = addressStart + 8; + for (int address = addressStart; address < addressEnd; address++) { + graphicsDirty[address] = true; + apple.graphicsDirty[address] = false; + } + } + + /** + * Set hires buffer dirty + */ + private void setHiresBufferDirty(int baseAddress) { + // Update dirty + int addressStart = baseAddress >> 7; + int addressEnd = addressStart + 8; + for (int address = addressStart; address < addressEnd; address++) { + graphicsDirty[address] = true; + apple.graphicsDirty[address + (0x0000 >> 7)] = false; + apple.graphicsDirty[address + (0x0400 >> 7)] = false; + apple.graphicsDirty[address + (0x0800 >> 7)] = false; + apple.graphicsDirty[address + (0x0c00 >> 7)] = false; + apple.graphicsDirty[address + (0x1000 >> 7)] = false; + apple.graphicsDirty[address + (0x1400 >> 7)] = false; + apple.graphicsDirty[address + (0x1800 >> 7)] = false; + apple.graphicsDirty[address + (0x1c00 >> 7)] = false; + } + } + + /** + * Is text buffer dirty? + */ + private boolean isTextBufferDirty(int baseAddress) { + boolean isDirty = false; + + // Update dirty + int addressStart = baseAddress >> 7; + int addressEnd = addressStart + 8; + for (int address = addressStart; address < addressEnd; address++) { + graphicsDirty[address] = apple.graphicsDirty[address]; + apple.graphicsDirty[address] = false; + if (graphicsDirty[address]) { + isDirty = true; + } + } + + return isDirty; + } + + /** + * Is hires buffer dirty? + */ + private boolean isHiresBufferDirty(int baseAddress) { + boolean isDirty = false; + + // Update dirty + int addressStart = baseAddress >> 7; + int addressEnd = addressStart + 8; + for (int address = addressStart; address < addressEnd; address++) { + graphicsDirty[address] = + apple.graphicsDirty[address + (0x0000 >> 7)] || + apple.graphicsDirty[address + (0x0400 >> 7)] || + apple.graphicsDirty[address + (0x0800 >> 7)] || + apple.graphicsDirty[address + (0x0c00 >> 7)] || + apple.graphicsDirty[address + (0x1000 >> 7)] || + apple.graphicsDirty[address + (0x1400 >> 7)] || + apple.graphicsDirty[address + (0x1800 >> 7)] || + apple.graphicsDirty[address + (0x1c00 >> 7)]; + apple.graphicsDirty[address + (0x0000 >> 7)] = false; + apple.graphicsDirty[address + (0x0400 >> 7)] = false; + apple.graphicsDirty[address + (0x0800 >> 7)] = false; + apple.graphicsDirty[address + (0x0c00 >> 7)] = false; + apple.graphicsDirty[address + (0x1000 >> 7)] = false; + apple.graphicsDirty[address + (0x1400 >> 7)] = false; + apple.graphicsDirty[address + (0x1800 >> 7)] = false; + apple.graphicsDirty[address + (0x1c00 >> 7)] = false; + if (graphicsDirty[address]) { + isDirty = true; + } + } + + return isDirty; + } + + /** + * Display precalculation + */ + private void precalcDisplay() { + // Display scaled size + apple.view.setDisplayScaledSizeX((int) (DISPLAY_SIZE_X * displayScale / 2)); + apple.view.setDisplayScaledSizeY((int) (DISPLAY_SIZE_Y * displayScale)); + + // Prepare display palette + setDisplayPalette(); + + // Prepare character set + loadCharSet(); + + // Prepare hires graphics + precalcHiresLookup(); + } + + private static final int CHARSET_SOURCE_CHAR_COUNT = 128; + private static final int CHARSET_SOURCE_SIZE_X = CHARSET_SOURCE_CHAR_COUNT * CHARSET_CHAR_SIZE_X; + private static final int CHARSET_SOURCE_SIZE_Y = CHARSET_CHAR_SIZE_Y; + + /** + * Precalculate charSet + */ + private void loadCharSet() { + int charSetOffset = 0; + + // Get RGB image + Object resource = apple.view.getCharSet(charSet, CHARSET_SOURCE_SIZE_X, CHARSET_SOURCE_SIZE_Y, CHARSET_SIZE_X); + + // Duplicate and invert + for (int charSetPosY = 0; charSetPosY < CHARSET_SIZE_Y; charSetPosY++) { + for (int charSetPosX = 0; charSetPosX < CHARSET_SOURCE_SIZE_X; charSetPosX++) { + charSet[charSetOffset + CHARSET_SOURCE_SIZE_X + charSetPosX] = + charSet[charSetOffset + charSetPosX] ^ 0xffffff; + } + charSetOffset += CHARSET_SIZE_X; + } + + // Colorize + for (charSetOffset = 0; charSetOffset < (CHARSET_SIZE_X * CHARSET_SIZE_Y); charSetOffset++) { + charSet[charSetOffset] &= (displayPalette[0xf] | 0xff000000); + } + +//apple.view.debug("here"); + apple.view.flushCharSet(resource); + } + + /** + * Precalculate char map + */ + private void precalcCharMaps() { + for (int index = 0; index < 3; index++) { + for (int character = 0; character < 0x100; character++) { + charMaps[index][character] = charMapLookup[index][character >> 5] + (character & 0x1f); + } + } + } + + /** + * Set char map + */ + private void setCharMap(int value) { + charMap = charMaps[value]; + } + + /** + * Set lores palette + */ + private void setDisplayPalette() { + displayPalette = (colorMode == COLORMODE_COLOR) ? displayPaletteColor : displayPaletteGreen; + doubleHiresPalette = (colorMode == COLORMODE_COLOR) ? doubleHiresPaletteColor : displayPaletteGreen; + } + + /** + * Precalculate hires even odd to word + */ + private void precalcHiresEvenEddToWord() { + for (int value = 0; value < 0x200; value++) { + hiresEvenOddToWord[value] = + ((value & 0x01) << 0) | + ((value & 0x01) << 1) | + ((value & 0x02) << 1) | + ((value & 0x02) << 2) | + ((value & 0x04) << 2) | + ((value & 0x04) << 3) | + ((value & 0x08) << 3) | + ((value & 0x08) << 4) | + ((value & 0x10) << 4) | + ((value & 0x10) << 5) | + ((value & 0x20) << 5) | + ((value & 0x20) << 6) | + ((value & 0x40) << 6) | + ((value & 0x40) << 7); + + if ((value & 0x80) != 0) { + hiresEvenOddToWord[value] <<= 1; + hiresEvenOddToWord[value] |= ((value & 0x100) >> 8); + } + } + } + + /** + * Precalculate hires + */ + private void precalcHiresLookup() { + if (colorMode == COLORMODE_COLOR) { + for (int value = 0; value < 0x100; value++) { + hiresLookup[value] = hiresLookupColor[((value << 6) & 0xff) | (value >> 2)]; + } + } else { + for (int value = 0; value < 0x100; value++) { + hiresLookup[value] = + (((value & 0x04) != 0) ? 0x000f : 0) | + (((value & 0x08) != 0) ? 0x00f0 : 0) | + (((value & 0x10) != 0) ? 0x0f00 : 0) | + (((value & 0x20) != 0) ? 0xf000 : 0); + } + } + } + + /** + * Render text canvas + */ + private final void renderTextScanLine(int destOffset, int sourceOffset) { + displayImageBuffer[destOffset + 0] = displayImageBuffer[destOffset + 1] = charSet[sourceOffset]; + displayImageBuffer[destOffset + 2] = displayImageBuffer[destOffset + 3] = charSet[sourceOffset + 1]; + displayImageBuffer[destOffset + 4] = displayImageBuffer[destOffset + 5] = charSet[sourceOffset + 2]; + displayImageBuffer[destOffset + 6] = displayImageBuffer[destOffset + 7] = charSet[sourceOffset + 3]; + displayImageBuffer[destOffset + 8] = displayImageBuffer[destOffset + 9] = charSet[sourceOffset + 4]; + displayImageBuffer[destOffset + 10] = displayImageBuffer[destOffset + 11] = charSet[sourceOffset + 5]; + displayImageBuffer[destOffset + 12] = displayImageBuffer[destOffset + 13] = charSet[sourceOffset + 6]; + } + + private final void renderTextCharacter(int destOffset, int sourceOffset) { + renderTextScanLine(destOffset, sourceOffset); + destOffset += DISPLAY_SIZE_X; sourceOffset += CHARSET_SIZE_X; + renderTextScanLine(destOffset, sourceOffset); + destOffset += DISPLAY_SIZE_X; sourceOffset += CHARSET_SIZE_X; + renderTextScanLine(destOffset, sourceOffset); + destOffset += DISPLAY_SIZE_X; sourceOffset += CHARSET_SIZE_X; + renderTextScanLine(destOffset, sourceOffset); + destOffset += DISPLAY_SIZE_X; sourceOffset += CHARSET_SIZE_X; + renderTextScanLine(destOffset, sourceOffset); + destOffset += DISPLAY_SIZE_X; sourceOffset += CHARSET_SIZE_X; + renderTextScanLine(destOffset, sourceOffset); + destOffset += DISPLAY_SIZE_X; sourceOffset += CHARSET_SIZE_X; + renderTextScanLine(destOffset, sourceOffset); + destOffset += DISPLAY_SIZE_X; sourceOffset += CHARSET_SIZE_X; + renderTextScanLine(destOffset, sourceOffset); + } + + private void renderText(int baseAddress, boolean isMixedMode) { + int screenCharY, screenCharYStart = isMixedMode ? 20 : 0; + int displayOffset; + int address, addressEnd, addressStart; + + displayOffset = screenCharYStart * DISPLAY_CHAR_SIZE_Y * DISPLAY_SIZE_X; + for (screenCharY = screenCharYStart; screenCharY < 24; screenCharY++) { + addressStart = baseAddress + textLineAddress[screenCharY]; + + if (graphicsDirty[addressStart >> 7]) { + addressEnd = addressStart + 40; + + for (address = addressStart; address < addressEnd; address++) { + renderTextCharacter(displayOffset, charMap[apple.mem[address] & 0xff] << 3); + displayOffset += DISPLAY_CHAR_SIZE_X * 2; + } + displayOffset += (DISPLAY_CHAR_SIZE_Y - 1) * DISPLAY_SIZE_X; + } else { + displayOffset += DISPLAY_CHAR_SIZE_Y * DISPLAY_SIZE_X; + } + } + } + + /** + * Render double text canvas + */ + private final void renderDoubleTextScanLine(int destOffset, int sourceOffset) { + displayImageBuffer[destOffset + 0] = charSet[sourceOffset]; + displayImageBuffer[destOffset + 1] = charSet[sourceOffset + 1]; + displayImageBuffer[destOffset + 2] = charSet[sourceOffset + 2]; + displayImageBuffer[destOffset + 3] = charSet[sourceOffset + 3]; + displayImageBuffer[destOffset + 4] = charSet[sourceOffset + 4]; + displayImageBuffer[destOffset + 5] = charSet[sourceOffset + 5]; + displayImageBuffer[destOffset + 6] = charSet[sourceOffset + 6]; + } + + private final void renderDoubleTextCharacter(int destOffset, int sourceOffset) { + renderDoubleTextScanLine(destOffset, sourceOffset); + destOffset += DISPLAY_SIZE_X; sourceOffset += CHARSET_SIZE_X; + renderDoubleTextScanLine(destOffset, sourceOffset); + destOffset += DISPLAY_SIZE_X; sourceOffset += CHARSET_SIZE_X; + renderDoubleTextScanLine(destOffset, sourceOffset); + destOffset += DISPLAY_SIZE_X; sourceOffset += CHARSET_SIZE_X; + renderDoubleTextScanLine(destOffset, sourceOffset); + destOffset += DISPLAY_SIZE_X; sourceOffset += CHARSET_SIZE_X; + renderDoubleTextScanLine(destOffset, sourceOffset); + destOffset += DISPLAY_SIZE_X; sourceOffset += CHARSET_SIZE_X; + renderDoubleTextScanLine(destOffset, sourceOffset); + destOffset += DISPLAY_SIZE_X; sourceOffset += CHARSET_SIZE_X; + renderDoubleTextScanLine(destOffset, sourceOffset); + destOffset += DISPLAY_SIZE_X; sourceOffset += CHARSET_SIZE_X; + renderDoubleTextScanLine(destOffset, sourceOffset); + } + + private void renderDoubleText(int baseAddress, boolean isMixedMode) { + int screenCharY, screenCharYStart = isMixedMode ? 20 : 0; + int displayOffset; + int address, addressEnd, addressStart; + + displayOffset = screenCharYStart * DISPLAY_CHAR_SIZE_Y * DISPLAY_SIZE_X; + for (screenCharY = screenCharYStart; screenCharY < 24; screenCharY++) { + addressStart = baseAddress + textLineAddress[screenCharY]; + + if (graphicsDirty[addressStart >> 7]) { + addressEnd = addressStart + 40; + + for (address = addressStart; address < addressEnd; address++) { + renderDoubleTextCharacter(displayOffset, charMap[apple.mem[address + 0x10000] & 0xff] << 3); + displayOffset += DISPLAY_CHAR_SIZE_X; + renderDoubleTextCharacter(displayOffset, charMap[apple.mem[address + 0x00000] & 0xff] << 3); + displayOffset += DISPLAY_CHAR_SIZE_X; + } + displayOffset += (DISPLAY_CHAR_SIZE_Y - 1) * DISPLAY_SIZE_X; + } else { + displayOffset += DISPLAY_CHAR_SIZE_Y * DISPLAY_SIZE_X; + } + } + } + + /** + * Render lores canvas + */ + private final void renderLoresScanLine(int destOffset, int color) { + displayImageBuffer[destOffset + 0] = color; + displayImageBuffer[destOffset + 1] = color; + displayImageBuffer[destOffset + 2] = color; + displayImageBuffer[destOffset + 3] = color; + displayImageBuffer[destOffset + 4] = color; + displayImageBuffer[destOffset + 5] = color; + displayImageBuffer[destOffset + 6] = color; + } + + private final void renderLoresBlock(int destOffset, int colorTop, int colorBottom) { + renderLoresScanLine(destOffset, colorTop); + destOffset += DISPLAY_SIZE_X; + renderLoresScanLine(destOffset, colorTop); + destOffset += DISPLAY_SIZE_X; + renderLoresScanLine(destOffset, colorTop); + destOffset += DISPLAY_SIZE_X; + renderLoresScanLine(destOffset, colorTop); + destOffset += DISPLAY_SIZE_X; + renderLoresScanLine(destOffset, colorBottom); + destOffset += DISPLAY_SIZE_X; + renderLoresScanLine(destOffset, colorBottom); + destOffset += DISPLAY_SIZE_X; + renderLoresScanLine(destOffset, colorBottom); + destOffset += DISPLAY_SIZE_X; + renderLoresScanLine(destOffset, colorBottom); + } + + private void renderLores(int baseAddress, boolean isMixedMode) { + int screenCharY, screenCharYEnd = isMixedMode ? 20 : 24; + int displayOffset; + int address, addressEnd, addressStart; + + displayOffset = 0; + for (screenCharY = 0; screenCharY < screenCharYEnd; screenCharY++) { + addressStart = baseAddress + textLineAddress[screenCharY]; + + if (graphicsDirty[addressStart >> 7]) { + addressEnd = addressStart + 40; + + for (address = addressStart; address < addressEnd; address++) { + renderLoresBlock(displayOffset, + displayPalette[apple.mem[address] & 0xf], + displayPalette[(apple.mem[address] & 0xf0) >> 4]); + displayOffset += DISPLAY_CHAR_SIZE_X; + renderLoresBlock(displayOffset, + displayPalette[apple.mem[address] & 0xf], + displayPalette[(apple.mem[address] & 0xf0) >> 4]); + displayOffset += DISPLAY_CHAR_SIZE_X; + } + displayOffset += (DISPLAY_CHAR_SIZE_Y - 1) * DISPLAY_SIZE_X; + } else { + displayOffset += DISPLAY_CHAR_SIZE_Y * DISPLAY_SIZE_X; + } + } + } + + /** + * Render double lores canvas + */ + private void renderDoubleLores(int baseAddress, boolean isMixedMode) { + int screenCharY, screenCharYEnd = isMixedMode ? 20 : 24; + int displayOffset; + int address, addressEnd, addressStart; + + displayOffset = 0; + for (screenCharY = 0; screenCharY < screenCharYEnd; screenCharY++) { + addressStart = baseAddress + textLineAddress[screenCharY]; + + if (graphicsDirty[addressStart >> 7]) { + addressEnd = addressStart + 40; + + for (address = addressStart; address < addressEnd; address++) { + renderLoresBlock(displayOffset, + displayPalette[apple.mem[address + 0x10000] & 0xf], + displayPalette[(apple.mem[address + 0x10000] & 0xf0) >> 4]); + displayOffset += DISPLAY_CHAR_SIZE_X; + renderLoresBlock(displayOffset, + displayPalette[apple.mem[address] & 0xf], + displayPalette[(apple.mem[address] & 0xf0) >> 4]); + displayOffset += DISPLAY_CHAR_SIZE_X; + } + displayOffset += (DISPLAY_CHAR_SIZE_Y - 1) * DISPLAY_SIZE_X; + } else { + displayOffset += DISPLAY_CHAR_SIZE_Y * DISPLAY_SIZE_X; + } + } + } + + /** + * Render hires canvas + */ + private final void renderHiresWord(int destOffset, int hiresNibble) { + displayImageBuffer[destOffset + 0] = displayPalette[(hiresNibble >> 0) & 0xf]; + displayImageBuffer[destOffset + 1] = displayPalette[(hiresNibble >> 4) & 0xf]; + displayImageBuffer[destOffset + 2] = displayPalette[(hiresNibble >> 8) & 0xf]; + displayImageBuffer[destOffset + 3] = displayPalette[(hiresNibble >> 12) & 0xf]; + } + + private final void renderHiresScanLine(int destOffset, int hiresWord) { + renderHiresWord(destOffset + 0, hiresLookup[(hiresWord >> 0) & 0xff]); + renderHiresWord(destOffset + 4, hiresLookup[(hiresWord >> 4) & 0xff]); + renderHiresWord(destOffset + 8, hiresLookup[(hiresWord >> 8) & 0xff]); + renderHiresWord(destOffset + 12, hiresLookup[(hiresWord >> 12) & 0xff]); + renderHiresWord(destOffset + 16, hiresLookup[(hiresWord >> 16) & 0xff]); + renderHiresWord(destOffset + 20, hiresLookup[(hiresWord >> 20) & 0xff]); + renderHiresWord(destOffset + 24, hiresLookup[(hiresWord >> 24) & 0xff]); + } + + private final void renderHiresBlock(int destOffset) { + renderHiresScanLine(destOffset, hiresWord[0]); destOffset += DISPLAY_SIZE_X; + renderHiresScanLine(destOffset, hiresWord[1]); destOffset += DISPLAY_SIZE_X; + renderHiresScanLine(destOffset, hiresWord[2]); destOffset += DISPLAY_SIZE_X; + renderHiresScanLine(destOffset, hiresWord[3]); destOffset += DISPLAY_SIZE_X; + renderHiresScanLine(destOffset, hiresWord[4]); destOffset += DISPLAY_SIZE_X; + renderHiresScanLine(destOffset, hiresWord[5]); destOffset += DISPLAY_SIZE_X; + renderHiresScanLine(destOffset, hiresWord[6]); destOffset += DISPLAY_SIZE_X; + renderHiresScanLine(destOffset, hiresWord[7]); + } + + private final void resetHiresWords() { + hiresWord[0] = 0; + hiresWord[1] = 0; + hiresWord[2] = 0; + hiresWord[3] = 0; + hiresWord[4] = 0; + hiresWord[5] = 0; + hiresWord[6] = 0; + hiresWord[7] = 0; + } + + private final void bufferHiresWords() { + hiresWord[0] = hiresWordNext[0]; + hiresWord[1] = hiresWordNext[1]; + hiresWord[2] = hiresWordNext[2]; + hiresWord[3] = hiresWordNext[3]; + hiresWord[4] = hiresWordNext[4]; + hiresWord[5] = hiresWordNext[5]; + hiresWord[6] = hiresWordNext[6]; + hiresWord[7] = hiresWordNext[7]; + } + + private final void calcNextHiresWord(int hiresWordIndex, int byteEven, int byteOdd) { + hiresWordNext[hiresWordIndex] = hiresWord[hiresWordIndex] >> 28; + hiresWordNext[hiresWordIndex] |= + hiresEvenOddToWord[(byteEven & 0xff) | ((hiresWordNext[hiresWordIndex] & 0x2) << 7)] << 2; + hiresWordNext[hiresWordIndex] |= + hiresEvenOddToWord[(byteOdd & 0xff) | ((hiresWordNext[hiresWordIndex] & 0x8000) >> 7)] << 16; + hiresWord[hiresWordIndex] |= (hiresWordNext[hiresWordIndex] << 28); + } + + private final void calcNextHiresWords(int address) { + calcNextHiresWord(0, apple.mem[address + 0x00000], apple.mem[address + 0x00001]); + calcNextHiresWord(1, apple.mem[address + 0x00400], apple.mem[address + 0x00401]); + calcNextHiresWord(2, apple.mem[address + 0x00800], apple.mem[address + 0x00801]); + calcNextHiresWord(3, apple.mem[address + 0x00c00], apple.mem[address + 0x00c01]); + calcNextHiresWord(4, apple.mem[address + 0x01000], apple.mem[address + 0x01001]); + calcNextHiresWord(5, apple.mem[address + 0x01400], apple.mem[address + 0x01401]); + calcNextHiresWord(6, apple.mem[address + 0x01800], apple.mem[address + 0x01801]); + calcNextHiresWord(7, apple.mem[address + 0x01c00], apple.mem[address + 0x01c01]); + } + + private void renderHires(int baseAddress, boolean isMixedMode) { + int screenCharY, screenCharYEnd = isMixedMode ? 20 : 24; + int displayOffset; + int address, addressEnd, addressStart; + + displayOffset = 0; + for (screenCharY = 0; screenCharY < screenCharYEnd; screenCharY++) { + addressStart = baseAddress + textLineAddress[screenCharY]; + + if (graphicsDirty[addressStart >> 7]) { + addressEnd = addressStart + 40; + + resetHiresWords(); + calcNextHiresWords(addressStart); + for (address = (addressStart + 2); address < addressEnd; address += 2) { + bufferHiresWords(); + calcNextHiresWords(address); + renderHiresBlock(displayOffset); + displayOffset += DISPLAY_CHAR_SIZE_X * 4; + } + bufferHiresWords(); + renderHiresBlock(displayOffset); + displayOffset += DISPLAY_CHAR_SIZE_X * 4; + + displayOffset += (DISPLAY_CHAR_SIZE_Y - 1) * DISPLAY_SIZE_X; + } else { + displayOffset += DISPLAY_CHAR_SIZE_Y * DISPLAY_SIZE_X; + } + } + } + + /** + * Render double hires canvas + */ + private final void renderDoubleHiresWord(int destOffset, int hiresNibble) { + displayImageBuffer[destOffset + 0] = doubleHiresPalette[(hiresNibble >> 0) & 0xf]; + displayImageBuffer[destOffset + 1] = doubleHiresPalette[(hiresNibble >> 4) & 0xf]; + displayImageBuffer[destOffset + 2] = doubleHiresPalette[(hiresNibble >> 8) & 0xf]; + displayImageBuffer[destOffset + 3] = doubleHiresPalette[(hiresNibble >> 12) & 0xf]; + } + + private final void renderDoubleHiresScanLine(int destOffset, int hiresWord) { + renderDoubleHiresWord(destOffset + 0, hiresLookup[(hiresWord >> 0) & 0xff]); + renderDoubleHiresWord(destOffset + 4, hiresLookup[(hiresWord >> 4) & 0xff]); + renderDoubleHiresWord(destOffset + 8, hiresLookup[(hiresWord >> 8) & 0xff]); + renderDoubleHiresWord(destOffset + 12, hiresLookup[(hiresWord >> 12) & 0xff]); + renderDoubleHiresWord(destOffset + 16, hiresLookup[(hiresWord >> 16) & 0xff]); + renderDoubleHiresWord(destOffset + 20, hiresLookup[(hiresWord >> 20) & 0xff]); + renderDoubleHiresWord(destOffset + 24, hiresLookup[(hiresWord >> 24) & 0xff]); + } + + private final void renderDoubleHiresBlock(int destOffset) { + renderDoubleHiresScanLine(destOffset, hiresWord[0]); destOffset += DISPLAY_SIZE_X; + renderDoubleHiresScanLine(destOffset, hiresWord[1]); destOffset += DISPLAY_SIZE_X; + renderDoubleHiresScanLine(destOffset, hiresWord[2]); destOffset += DISPLAY_SIZE_X; + renderDoubleHiresScanLine(destOffset, hiresWord[3]); destOffset += DISPLAY_SIZE_X; + renderDoubleHiresScanLine(destOffset, hiresWord[4]); destOffset += DISPLAY_SIZE_X; + renderDoubleHiresScanLine(destOffset, hiresWord[5]); destOffset += DISPLAY_SIZE_X; + renderDoubleHiresScanLine(destOffset, hiresWord[6]); destOffset += DISPLAY_SIZE_X; + renderDoubleHiresScanLine(destOffset, hiresWord[7]); + } + + private final void calcNextDoubleHiresWord(int hiresWordIndex, int byte1, int byte2, int byte3, int byte4) { + hiresWordNext[hiresWordIndex] = ( + ((byte1 & 0x7f) << 2) | ((byte2 & 0x7f) << 9) | + ((byte3 & 0x7f) << 16) | ((byte4 & 0x7f) << 23) | + (hiresWord[hiresWordIndex] >> 28)); + hiresWord[hiresWordIndex] |= (hiresWordNext[hiresWordIndex] << 28); + } + + private final void calcNextDoubleHiresWords(int address) { + calcNextDoubleHiresWord(0, + apple.mem[address + 0x10000], apple.mem[address + 0x00000], + apple.mem[address + 0x10001], apple.mem[address + 0x00001]); + calcNextDoubleHiresWord(1, + apple.mem[address + 0x10400], apple.mem[address + 0x00400], + apple.mem[address + 0x10401], apple.mem[address + 0x00401]); + calcNextDoubleHiresWord(2, + apple.mem[address + 0x10800], apple.mem[address + 0x00800], + apple.mem[address + 0x10801], apple.mem[address + 0x00801]); + calcNextDoubleHiresWord(3, + apple.mem[address + 0x10c00], apple.mem[address + 0x00c00], + apple.mem[address + 0x10c01], apple.mem[address + 0x00c01]); + calcNextDoubleHiresWord(4, + apple.mem[address + 0x11000], apple.mem[address + 0x01000], + apple.mem[address + 0x11001], apple.mem[address + 0x01001]); + calcNextDoubleHiresWord(5, + apple.mem[address + 0x11400], apple.mem[address + 0x01400], + apple.mem[address + 0x11401], apple.mem[address + 0x01401]); + calcNextDoubleHiresWord(6, + apple.mem[address + 0x11800], apple.mem[address + 0x01800], + apple.mem[address + 0x11801], apple.mem[address + 0x01801]); + calcNextDoubleHiresWord(7, + apple.mem[address + 0x11c00], apple.mem[address + 0x01c00], + apple.mem[address + 0x11c01], apple.mem[address + 0x01c01]); + } + + private void renderDoubleHires(int baseAddress, boolean isMixedMode) { + int screenCharY, screenCharYEnd = isMixedMode ? 20 : 24; + int displayOffset; + int address, addressEnd, addressStart; + + displayOffset = 0; + for (screenCharY = 0; screenCharY < screenCharYEnd; screenCharY++) { + addressStart = baseAddress + textLineAddress[screenCharY]; + + if (graphicsDirty[addressStart >> 7]) { + addressEnd = addressStart + 40; + + resetHiresWords(); + calcNextDoubleHiresWords(addressStart); + for (address = (addressStart + 2); address < addressEnd; address += 2) { + bufferHiresWords(); + calcNextDoubleHiresWords(address); + renderDoubleHiresBlock(displayOffset); + displayOffset += DISPLAY_CHAR_SIZE_X * 4; + } + bufferHiresWords(); + renderDoubleHiresBlock(displayOffset); + displayOffset += DISPLAY_CHAR_SIZE_X * 4; + + displayOffset += (DISPLAY_CHAR_SIZE_Y - 1) * DISPLAY_SIZE_X; + } else { + displayOffset += DISPLAY_CHAR_SIZE_Y * DISPLAY_SIZE_X; + } + } + } +} diff --git a/src/main/java/vavi/apps/appleii/AppleIIApp.java b/src/main/java/vavi/apps/appleii/AppleIIApp.java new file mode 100644 index 0000000..13d3d20 --- /dev/null +++ b/src/main/java/vavi/apps/appleii/AppleIIApp.java @@ -0,0 +1,1269 @@ +/* + * Copyright (c) 2008 by umjammer, All rights reserved. + * + * Programmed by umjammer + * + * Released under the GPL + */ + +package vavi.apps.appleii; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Container; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.MediaTracker; +import java.awt.Toolkit; +import java.awt.event.InputEvent; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionAdapter; +import java.awt.event.MouseMotionListener; +import java.awt.image.BufferedImage; +import java.awt.image.MemoryImageSource; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; +import java.util.StringTokenizer; +import java.util.zip.GZIPInputStream; + +import javax.tv.xlet.Xlet; +import javax.tv.xlet.XletContext; + +import org.havi.ui.HScene; +import org.havi.ui.HSceneFactory; + + +/** + * AppleIIApp. + * + * @author umjammer + * @version 0.00 080912 umjammer initial version
+ */ +public class AppleIIApp implements Xlet { + + /** */ + private HScene scene; + /** */ + private MyView gui; + /** */ +// private XletContext context; + + /* */ + public void initXlet(XletContext context) { +// this.context = context; + + this.scene = HSceneFactory.getInstance().getDefaultHScene(); + + try { + this.gui = new MyView(); + + gui.setSize(1920, 1080); + scene.add(gui, BorderLayout.CENTER); + } catch (Throwable e) { +e.printStackTrace(System.err); + } + + scene.validate(); + } + + /* */ + public void startXlet() { + gui.setVisible(true); + scene.setVisible(true); + gui.requestFocus(); + + new Thread(gui).start(); + } + + /* */ + public void pauseXlet() { + gui.setVisible(false); + } + + /* */ + public void destroyXlet(boolean unconditional) { + scene.remove(gui); + scene = null; + } + + /** */ + private class MyView extends Container implements AppleIIGo.View, Runnable { + + private static final int MODE_INIT = 0; + private static final int MODE_NORMAL = 1; + private static final int MODE_VIRTUAL_KEYBOARD = 2; + private static final int MODE_DIRECT = 3; + private static final int MODE_DISK1 = 4; + private static final int MODE_DISK2 = 5; + + private int mode = MODE_INIT; + + private AppleIIGo game; + + private KeyBoard keyBoard; + private NormalVC normalVC; + private DirectVC directVC; + private DiskVC[] diskVCs = new DiskVC[2]; + private GameVC gameVC; + + /** + *

 
+         *  1
+         *  2
+         *  3
+         *  4
+         *  5   toggleStatMode
+         *  6   toggleStepMode
+         *  7   stepInstructions 1
+         *  8   stepInstructions 128
+         *  9   setVolume true
+         *  0   setVolume false
+         *  B   mode change
+         *  R
+         *  G   restart
+         *  Y   reset
+         *  O   pad button right
+         *  #   pad button left   
+         *  U   pad up
+         *  L   pad left
+         *  R   pad right
+         *  D   pad down
+         * 
+ */ + class NormalVC { + + /** O, # */ + long lastPressed[] = new long[2]; + + NormalVC() { + // xletview doesn't have key release capability! + if (!releasable) { + new Thread(new Runnable() { + public void run() { +System.err.println("RELEASE THREAD: start"); + try { + while (true) { + Thread.sleep(100); + if (System.currentTimeMillis() - lastPressed[0] > 100) { + game.setButton(0, false); + } + if (System.currentTimeMillis() - lastPressed[1] > 100) { + game.setButton(1, false); + } + } + } catch (Throwable t) { +t.printStackTrace(System.err); +debug(t); + } + } + }).start(); + } + } + + /* */ + void keyPressed(KeyEvent e) { + int keyCode = e.getKeyCode(); +System.err.println("NORMAL: " + keyCode); + switch(keyCode) { + case KeyEvent.VK_1: // 1 + // user mapped ? + break; + case KeyEvent.VK_2: // 2 + // user mapped ? + break; + case KeyEvent.VK_3: // 3 + // user mapped ? + break; + case KeyEvent.VK_4: // 4 + // user mapped ? + break; + case KeyEvent.VK_5: // 5 + if (game.isCpuDebugEnabled()) { + game.toggleStatMode(); + } + break; + case KeyEvent.VK_6: // 6 + if (game.isCpuDebugEnabled()) { + game.toggleStepMode(); + } + break; + case KeyEvent.VK_7: // 7 + if (game.isCpuDebugEnabled()) { + game.stepInstructions(1); + } + break; + case KeyEvent.VK_8: // 8 + if (game.isCpuDebugEnabled()) { + game.stepInstructions(128); + } + break; + case KeyEvent.VK_9: // 9 + game.setVolume(true); + break; + case KeyEvent.VK_0: // 0 + game.setVolume(false); + break; + case 403: // B + mode = MODE_VIRTUAL_KEYBOARD; +game.setPaddle(0, Paddle.PADDLE_CENTER); +game.setPaddle(1, Paddle.PADDLE_CENTER); +System.err.println("mode: -> MODE_VIRTUAL_KEYBOARD"); + break; + case 404: // R + // user mapped ? + break; + case 405: // G +stat.clear(); + game.restart(); + break; + case 406: // Y +stat.clear(); + game.reset(); + break; + case KeyEvent.VK_ENTER: // O +case KeyEvent.VK_X: // for emulator + game.setButton(0, true); + if (!releasable) { + lastPressed[0] = System.currentTimeMillis(); + } + break; + case 461: // # +case KeyEvent.VK_Z: // for emulator + game.setButton(1, true); + if (!releasable) { + lastPressed[1] = System.currentTimeMillis(); + } + break; + case KeyEvent.VK_LEFT: // L + game.setPaddle(0, Paddle.PADDLE_LOW); + break; + case KeyEvent.VK_UP: // U + game.setPaddle(1, Paddle.PADDLE_LOW); + break; + case KeyEvent.VK_DOWN: // D + game.setPaddle(1, Paddle.PADDLE_HIGH); + break; + case KeyEvent.VK_RIGHT: // R + game.setPaddle(0, Paddle.PADDLE_HIGH); + break; + } + } + + /* */ + void keyReleased(KeyEvent e) { + int keyCode = e.getKeyCode(); +//debug("KEY RELEASED: " + e.getKeyCode()); + if (releasable) { + switch(keyCode) { + case KeyEvent.VK_ENTER: // O +case KeyEvent.VK_X: // for emulator + game.setButton(0, false); + break; + case 461: // # +case KeyEvent.VK_Z: // for emulator + game.setButton(1, false); + break; + case KeyEvent.VK_LEFT: // L + game.setPaddle(0, Paddle.PADDLE_CENTER); + break; + case KeyEvent.VK_UP: // U + game.setPaddle(1, Paddle.PADDLE_CENTER); + break; + case KeyEvent.VK_DOWN: // D + game.setPaddle(1, Paddle.PADDLE_CENTER); + break; + case KeyEvent.VK_RIGHT: // R + game.setPaddle(0, Paddle.PADDLE_CENTER); + break; + } + } + } + + final int Y = 384; + /* */ + public void paint(Graphics g) { + g.setColor(Color.black); + g.fillRect(0, Y, 560, 540); + if (debug) { + g.setColor(Color.white); + g.drawString(" Normal Mode: releasable: " + releasable, 0, Y + 36); + g.drawString(" 1: " + game.getDiskDriveResource(0), 0, Y + 36 * 2); + g.drawString(" 2: " + game.getDiskDriveResource(1), 0, Y + 36 * 3); + } + } + } + + /** + *
+         *  B   mode change
+         *  G   restart
+         *  O   insert
+         *  #   release
+         *  U   disk previous
+         *  D   disk next
+         * 
+ */ + class DiskVC { + Image image; + int drive; + File[] files; + /** has createImage */ + DiskVC(int drive) { + this.drive = drive; + this.image = createImage("/disk.png"); + String root = System.getProperty("bluray.vfs.root", "../tmp"); + File file = new File(root); +try { + files = file.listFiles(new FilenameFilter() { + public boolean accept(File dir, String name) { + return name.toLowerCase().endsWith(".dsk") || + name.toLowerCase().endsWith(".nib"); + } + }); +} catch (Throwable t) { // for xletview bug + t.printStackTrace(System.err); + files = new File[] { + new File(file, "Lode Runner.dsk"), + new File(file, "Mystery House.dsk"), + new File(file, "Tetris II.dsk"), + new File(file, "tzone1a.nib"), + new File(file, "tzone1b.nib"), + new File(file, "tzone2c.nib"), + new File(file, "tzone2d.nib"), + new File(file, "tzone3e.nib"), + new File(file, "tzone3f.nib"), + new File(file, "tzone4g.nib"), + new File(file, "tzone4h.nib"), + new File(file, "tzone5i.nib"), + new File(file, "tzone5j.nib"), + new File(file, "tzone6k.nib"), + new File(file, "tzone6l.nib"), + }; +} + } + int fileIndex; + void keyPressed(KeyEvent e) { + int keyCode = e.getKeyCode(); +System.err.println("DISK[" + drive + "]: " + keyCode); + switch (keyCode) { + case KeyEvent.VK_UP: + if (fileIndex > 0) { + fileIndex--; + } else { + fileIndex = files.length - 1; + } + name = files[fileIndex].getName(); + selectionMode = MODE_SELECTING; + break; + case KeyEvent.VK_DOWN: + if (fileIndex < files.length - 1) { + fileIndex++; + } else { + fileIndex = 0; + } + name = files[fileIndex].getName(); + selectionMode = MODE_SELECTING; + break; + case KeyEvent.VK_ENTER: + name = files[fileIndex].getName(); + game.mountDisk(drive, name); + selectionMode = MODE_SELECTED; + break; + case 461: // # +case KeyEvent.VK_Z: // for emulator + name = null; + game.mountDisk(drive, null); + selectionMode = MODE_SELECTED; + break; + case 403: // B + if (drive == 0) { + mode = MODE_DISK2; + diskVCs[1].init(); +System.err.println("mode: -> DISK2"); + } else { + if (debug) { + mode = MODE_DIRECT; +System.err.println("mode: -> DIRECT"); + } else { + mode = MODE_NORMAL; +System.err.println("mode: -> NORMAL"); + } + } + break; + case 405: // G +stat.clear(); + game.restart(); + break; + case 406: // Y +stat.clear(); + game.reset(); + } + } + String name; + final int MODE_SELECTING = 1; + final int MODE_SELECTED = 0; + int selectionMode; + void init() { + name = game.getDiskDriveResource(drive); +System.err.println("DRIVE[" + drive + "]: " + name); + selectionMode = MODE_SELECTED; + } + final int Y = 384; + /* */ + public void paint(Graphics g) { + g.setColor(Color.black); + g.fillRect(0, Y, 560, 540); + g.drawImage(image, 0, Y, MyView.this); + switch (selectionMode) { + case MODE_SELECTED: + g.setColor(Color.blue); + break; + case MODE_SELECTING: + g.setColor(Color.red); + break; + } + String label = (drive + 1) + ": " + (name == null || "".equals(name) ? "NO DISK" : name.substring(0, name.length() - 4)); + g.drawString(label, 16, Y + 36); + } + } + + /** for emulator */ + class DirectVC { + void keyPressed(KeyEvent e) { + int keyCode = e.getKeyCode(); +System.err.println("DIRECT: " + keyCode); + switch(keyCode) { + case KeyEvent.VK_LEFT: + game.setKeyLatch(8); + break; + case KeyEvent.VK_RIGHT: + game.setKeyLatch(21); + break; + case KeyEvent.VK_UP: + game.setKeyLatch(11); + break; + case KeyEvent.VK_DOWN: + game.setKeyLatch(10); + break; + case KeyEvent.VK_ESCAPE: + game.setKeyLatch(27); + break; + case KeyEvent.VK_BACK_SPACE: + game.setKeyLatch(127); + break; + case KeyEvent.VK_ENTER: + game.setKeyLatch(13); + break; + case 403: // B + mode = MODE_NORMAL; +game.setPaddle(0, Paddle.PADDLE_CENTER); +game.setPaddle(1, Paddle.PADDLE_CENTER); +System.err.println("mode: -> NORMAL"); + break; + case 405: // G +stat.clear(); + game.restart(); + break; + case 406: // Y +stat.clear(); + game.reset(); + default: + game.setKeyLatch(keyCode); + break; + } + } + + void mousePressed(MouseEvent e) { + int modifiers = e.getModifiers(); + + if ((modifiers & InputEvent.BUTTON3_MASK) != 0) { + game.setButton(0, true); + } + if ((modifiers & InputEvent.BUTTON1_MASK) != 0) { + game.setButton(1, true); + } + } + + void mouseReleased(MouseEvent e) { + int modifiers = e.getModifiers(); + + if ((modifiers & InputEvent.BUTTON3_MASK) != 0) { + game.setButton(0, false); + } + if ((modifiers & InputEvent.BUTTON1_MASK) != 0) { + game.setButton(1, false); + } + } + + void mouseDragged(MouseEvent e) { + mouseMoved(e); + } + + void mouseMoved(MouseEvent e) { + game.setPaddlePos(e.getX(), e.getY()); + } + + final int Y = 384; + /* */ + public void paint(Graphics g) { + g.setColor(Color.black); + g.fillRect(0, Y, 560, 540); + g.setColor(Color.white); + g.drawString(" Direct Mode", 0, Y + 36); + } + } + + /** */ + private KeyListener keyListener = new KeyAdapter() { + + public void keyPressed(KeyEvent e) { + switch (mode) { + case MODE_VIRTUAL_KEYBOARD: + keyBoard.keyPressed(e); + break; + case MODE_NORMAL: + normalVC.keyPressed(e); + break; + case MODE_DIRECT: + directVC.keyPressed(e); + break; + case MODE_DISK1: + diskVCs[0].keyPressed(e); + break; + case MODE_DISK2: + diskVCs[1].keyPressed(e); + break; + } + } + + public void keyReleased(KeyEvent e) { + switch (mode) { + case MODE_NORMAL: + normalVC.keyReleased(e); + break; + } + } + }; + + /** */ + private MouseListener mouseListener = new MouseAdapter() { + + public void mousePressed(MouseEvent e) { + switch (mode) { + case MODE_VIRTUAL_KEYBOARD: + keyBoard.mousePressed(e); + break; + case MODE_DIRECT: + directVC.mousePressed(e); + break; + } + } + + public void mouseReleased(MouseEvent e) { + switch (mode) { + case MODE_VIRTUAL_KEYBOARD: + keyBoard.mouseReleased(e); + break; + case MODE_DIRECT: + directVC.mouseReleased(e); + break; + } + } + }; + + /** */ + private MouseMotionListener mouseMotionListener = new MouseMotionAdapter() { + public void mouseDragged(MouseEvent e) { + switch (mode) { + case MODE_NORMAL: + break; + case MODE_DIRECT: + directVC.mouseDragged(e); + break; + } + } + + public void mouseMoved(MouseEvent e) { + switch (mode) { + case MODE_NORMAL: + break; + case MODE_DIRECT: + directVC.mouseMoved(e); + break; + } + } + }; + + /** */ + private boolean notified; + + /* */ + public void addNotify() { + super.addNotify(); + notified = true; + } + +List stat = new ArrayList(); +public void debug(String s) { + stat.add(s); +} +public void debug(Throwable t) { + t.printStackTrace(System.err); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintStream ps = new PrintStream(baos); + t.printStackTrace(ps); + String stackTraces = baos.toString(); + StringTokenizer st = new StringTokenizer(stackTraces, "\n"); + while (st.hasMoreTokens()) { + stat.add(st.nextToken()); + } +} + + /** */ + private boolean debug; + + /** */ + private boolean releasable; + + /** */ + MyView() throws IOException { + this.game = new AppleIIGo(); + game.setView(this); + AppleIIGo.Dao dao = new MyDao(); + game.setDao(dao); + debug = "true".equals(dao.getParameter("debugMode")); +System.err.println("DEBUG: " + debug); + releasable = "YES".equals(System.getProperty("bluray.rccapability.holdandrelease")); // "bluray.rccapability.release" +System.err.println("RELEASABLE: " + releasable); + + addKeyListener(keyListener); + addMouseListener(mouseListener); + addMouseMotionListener(mouseMotionListener); + } + + /** */ + public void run() { + while (!notified) { + Thread.yield(); + } +try { + game.init(); + + this.keyBoard = new KeyBoard(); + this.directVC = new DirectVC(); + this.normalVC = new NormalVC(); + this.diskVCs[0] = new DiskVC(0); + this.diskVCs[1] = new DiskVC(1); + this.gameVC = new GameVC(); + + mode = MODE_NORMAL; +System.err.println("mode: -> MODE_NORMAL"); + + game.start(); +} catch (Throwable t) { + debug(t); + repaint(); +} + } + + /** + *
 
+         *  B   mode change
+         *  G   restart
+         *  O   key select
+         *  U   key up
+         *  L   key left
+         *  R   key right
+         *  D   key down
+         * 
+ */ + class KeyBoard { + Image image; + int[][] bounds = { + { 6, 14, 22, 14 }, + { 31, 14, 22, 14 }, + { 56, 14, 22, 14 }, + { 82, 14, 22, 14 }, + { 107, 14, 22, 14 }, + { 133, 14, 22, 14 }, + { 159, 14, 22, 14 }, + { 184, 14, 22, 14 }, + { 209, 14, 22, 14 }, + { 235, 14, 22, 14 }, + { 260, 14, 22, 14 }, + { 286, 14, 22, 14 }, + { 311, 14, 22, 14 }, + { 337, 14, 22, 14 }, + + { 6, 31, 22, 20 }, + { 30, 31, 22, 20 }, + { 55, 31, 22, 20 }, + { 79, 31, 22, 20 }, + { 104, 31, 22, 20 }, + { 129, 31, 22, 20 }, + { 153, 31, 22, 20 }, + { 177, 31, 22, 20 }, + { 202, 31, 22, 20 }, + { 226, 31, 22, 20 }, + { 251, 31, 22, 20 }, + { 276, 31, 22, 20 }, + { 300, 31, 22, 20 }, + { 325, 31, 34, 20 }, + + { 6, 55, 34, 20 }, + { 42, 55, 22, 20 }, + { 67, 55, 22, 20 }, + { 91, 55, 22, 20 }, + { 115, 55, 22, 20 }, + { 140, 55, 22, 20 }, + { 165, 55, 22, 20 }, + { 189, 55, 22, 20 }, + { 214, 55, 22, 20 }, + { 239, 55, 22, 20 }, + { 263, 55, 22, 20 }, + { 288, 55, 22, 20 }, + { 312, 55, 22, 20 }, + { 337, 55, 22, 20 }, + + { 6, 79, 39, 20 }, + { 48, 79, 22, 20 }, + { 73, 79, 22, 20 }, + { 97, 79, 22, 20 }, + { 122, 79, 22, 20 }, + { 147, 79, 22, 20 }, + { 171, 79, 22, 20 }, + { 196, 79, 22, 20 }, + { 221, 79, 22, 20 }, + { 245, 79, 22, 20 }, + { 270, 79, 22, 20 }, + { 294, 79, 22, 20 }, + { 319, 79, 39, 20 }, + + { 6, 102, 52, 20 }, + { 60, 102, 22, 20 }, + { 85, 102, 22, 20 }, + { 110, 102, 22, 20 }, + { 134, 102, 22, 20 }, + { 159, 102, 22, 20 }, + { 184, 102, 22, 20 }, + { 208, 102, 22, 20 }, + { 233, 102, 22, 20 }, + { 258, 102, 22, 20 }, + { 282, 102, 22, 20 }, + { 307, 102, 52, 20 }, + + { 6, 126, 21, 24 }, + { 30, 126, 21, 24 }, + { 55, 126, 21, 24 }, + { 79, 126, 28, 24 }, + { 110, 126, 121, 24 }, + { 233, 126, 28, 24 }, + { 263, 126, 21, 24 }, + + { 288, 138, 22, 12 }, + { 313, 126, 22, 12 }, + { 313, 138, 22, 12 }, + { 337, 138, 22, 12 }, + }; + /** l, r, u, d */ + int[][] navigation = { + { 13, 1, 67, 14 }, + { 0, 2, 68, 15 }, + { 1, 3, 69, 16 }, + { 2, 4, 70, 17 }, + { 3, 5, 71, 18 }, + { 4, 6, 71, 19 }, + { 5, 7, 71, 20 }, + { 6, 8, 71, 21 }, + { 7, 9, 71, 22 }, + { 8, 10, 72, 23 }, + { 9, 11, 73, 24 }, + { 10, 12, 74, 25 }, + { 11, 13, 76, 26 }, + { 12, 0, 77, 27 }, + + { 27, 15, 0, 28 }, + { 14, 16, 1, 29 }, + { 15, 17, 2, 30 }, + { 16, 18, 3, 31 }, + { 17, 19, 4, 32 }, + { 18, 20, 5, 33 }, + { 19, 21, 6, 34 }, + { 20, 22, 7, 35 }, + { 21, 23, 8, 36 }, + { 22, 24, 9, 37 }, + { 23, 25, 10, 38 }, + { 24, 26, 11, 39 }, + { 25, 27, 12, 40 }, + { 26, 14, 13, 41 }, + + { 41, 29, 14, 42 }, + { 28, 30, 15, 43 }, + { 29, 31, 16, 44 }, + { 30, 32, 17, 45 }, + { 31, 33, 18, 46 }, + { 32, 34, 19, 47 }, + { 33, 35, 20, 48 }, + { 34, 36, 21, 49 }, + { 35, 37, 22, 50 }, + { 36, 38, 23, 51 }, + { 37, 39, 24, 52 }, + { 38, 40, 25, 53 }, + { 39, 41, 26, 54 }, + { 40, 28, 27, 54 }, + + { 54, 43, 28, 55 }, + { 42, 44, 29, 56 }, + { 43, 45, 30, 57 }, + { 44, 46, 31, 58 }, + { 45, 47, 32, 59 }, + { 46, 48, 33, 60 }, + { 47, 49, 34, 61 }, + { 48, 50, 35, 62 }, + { 49, 51, 36, 63 }, + { 50, 52, 37, 64 }, + { 51, 53, 38, 65 }, + { 52, 54, 39, 66 }, + { 53, 42, 40, 66 }, + + { 66, 56, 42, 67 }, + { 55, 57, 43, 69 }, + { 56, 58, 44, 70 }, + { 57, 59, 45, 71 }, + { 58, 60, 46, 71 }, + { 59, 61, 47, 71 }, + { 60, 62, 48, 71 }, + { 61, 63, 49, 71 }, + { 62, 64, 50, 72 }, + { 63, 65, 51, 73 }, + { 64, 66, 52, 74 }, + { 65, 67, 53, 75 }, + + { 77, 68, 55, 0 }, + { 67, 69, 55, 1 }, + { 68, 70, 56, 2 }, + { 69, 71, 57, 3 }, + { 70, 72, 60, 6 }, + { 71, 73, 63, 9 }, + { 72, 74, 64, 10 }, + + { 73, 75, 65, 11 }, + { 74, 77, 66, 76 }, + { 74, 77, 75, 12 }, + { 76, 67, 66, 13 }, + }; + /** has createImage */ + KeyBoard() { + this.image = createImage("/keyboard.png"); + } + final int Y = 384; + /* */ + public void paint(Graphics g) { + g.drawImage(image, 0, Y, MyView.this); + if (shiftIndex == 1) { + g.setColor(Color.blue); + g.drawRect(bounds[55][0], bounds[55][1] + Y, bounds[55][2], bounds[55][3]); + g.setColor(Color.blue); + g.drawRect(bounds[66][0], bounds[66][1] + Y, bounds[66][2], bounds[66][3]); + } + g.setColor(Color.red); + g.drawRect(bounds[keyIndex][0], bounds[keyIndex][1] + Y, bounds[keyIndex][2], bounds[keyIndex][3]); + } + int shiftIndex = 0; + final int KEY_SHIFT = -2; + int keyIndex; + /** normal, shift */ + int[][] keyDatum = { + { 0x1b, 0x1b }, // esc + { -1, -1 }, // f1 + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, // f12 + { -1, -1 }, // ? + + { '`', '~' }, + { '1', '!' }, + { '2', '@' }, + { '3', '#' }, + { '4', '$' }, + { '5', '%' }, + { '6', '^' }, + { '7', '&' }, + { '8', '*' }, + { '9', '(' }, + { '0', ')' }, + { '-', '_' }, + { '=', '+' }, + { 0x08, 0x08 }, // delete + + { 0x09, 0x09 }, // tab + { 'q', 'Q' }, + { 'w', 'W' }, + { 'e', 'E' }, + { 'r', 'R' }, + { 't', 'T' }, + { 'y', 'Y' }, + { 'u', 'U' }, + { 'i', 'I' }, + { 'o', 'O' }, + { 'p', 'P' }, + { '[', '{' }, + { ']', '}' }, + { '\\', '|' }, + + { -1, -1 }, // caps + { 'a', 'A' }, + { 's', 'S' }, + { 'd', 'D' }, + { 'f', 'F' }, + { 'g', 'G' }, + { 'h', 'H' }, + { 'j', 'J' }, + { 'k', 'K' }, + { 'l', 'L' }, + { ';', ':' }, + { '\'', '\"' }, + { 0x0d, 0x0d }, // enter + + { KEY_SHIFT, KEY_SHIFT }, // shift + { 'z', 'Z' }, + { 'x', 'X' }, + { 'c', 'C' }, + { 'v', 'V' }, + { 'b', 'B' }, + { 'n', 'N' }, + { 'm', 'M' }, + { ',', '<' }, + { '.', '>' }, + { '/', '?' }, + { KEY_SHIFT, KEY_SHIFT }, // shift + + { -1, -1 }, // fn + { -1, -1 }, // ctrl + { -1, -1 }, // option + { -1, -1 }, // command + { 0x20, 0x20 }, // space + { -1, -1 }, // command + { -1, -1 }, // option + { 8, 8 }, // left + { 11, 11 }, // up + { 10, 10 }, // down + { 21, 21 }, // right + }; + public void keyPressed(KeyEvent e) { +System.err.println("VK: " + e.getKeyCode()); + switch(e.getKeyCode()) { + case KeyEvent.VK_LEFT: + keyIndex = navigation[keyIndex][0]; + break; + case KeyEvent.VK_RIGHT: + keyIndex = navigation[keyIndex][1]; + break; + case KeyEvent.VK_UP: + keyIndex = navigation[keyIndex][2]; + break; + case KeyEvent.VK_DOWN: + keyIndex = navigation[keyIndex][3]; + break; + case KeyEvent.VK_ENTER: // O + keyPressed(); + break; + case 461: // # + // TODO toggle shift ? BS ? + break; + case 403: // B + mode = MODE_DISK1; + diskVCs[0].init(); +System.err.println("mode: -> DISK1"); + break; + case 405: // G +stat.clear(); + game.restart(); + case 406: // Y +stat.clear(); + game.reset(); + break; + } + } + private void keyPressed() { + int keyCode = keyDatum[keyIndex][shiftIndex]; + switch (keyCode) { + case KEY_SHIFT: + shiftIndex = 1 - shiftIndex; +System.err.println("VK: SHIFT: " + (shiftIndex == 1 ? "ON" : "OFF")); + break; + default: + game.setKeyLatch(keyCode); +System.err.println("VK: SEND: " + keyCode); + break; + } + } + public void mousePressed(MouseEvent e) { + int x = e.getX(); + int y = e.getY(); + for (int i = 0; i < bounds.length; i++) { + if (x >= bounds[i][0] && x <= bounds[i][0] + bounds[i][2] && + y >= bounds[i][1] + Y && y <= bounds[i][1] + Y + bounds[i][3]) { + keyIndex = i; + keyPressed(); + } + } + } + public void mouseReleased(MouseEvent e) { + } + } + + /* */ + public void paint(Graphics g) { +try { + if (gameVC != null) { + gameVC.paint(g); + switch (mode) { + case MODE_VIRTUAL_KEYBOARD: + keyBoard.paint(g); + break; + case MODE_NORMAL: + normalVC.paint(g); + break; + case MODE_DIRECT: + directVC.paint(g); + break; + case MODE_DISK1: + diskVCs[0].paint(g); + break; + case MODE_DISK2: + diskVCs[1].paint(g); + break; + } + } +} catch (Throwable t) { + debug(t); +} +if (stat.size() > 0) { + g.setColor(Color.red); + for (int i = 0; i < stat.size(); i++) { + g.drawString((String) stat.get(i), 0, 36 * i + 36); + } +} + } + + /** */ + class GameVC { + int displayScaledSizeX; + int displayScaledSizeY; + MemoryImageSource mis; + Image displayImage; + Image displayImagePaused; + Image displayImageGlare; + /** has createImage */ + GameVC() { + this.mis = new MemoryImageSource(AppleDisplay.DISPLAY_SIZE_X, AppleDisplay.DISPLAY_SIZE_Y, game.getDisplayImageBuffer(), 0, AppleDisplay.DISPLAY_SIZE_X); + mis.setAnimated(true); + mis.setFullBufferUpdates(true); + this.displayImage = createImage(mis); + + // Load glare and pause images + displayImageGlare = createImage("/Glare.png"); + displayImagePaused = createImage("/Paused.png"); + } + /** */ + void paint(Graphics g) { + + mis.newPixels(); + + g.drawImage(displayImage, + 0, 0, displayScaledSizeX, displayScaledSizeY, + 0, 0, AppleDisplay.DISPLAY_SIZE_X, AppleDisplay.DISPLAY_SIZE_Y, + MyView.this); + + if (game.isStatMode()) { + g.setColor(Color.black); + g.fillRect(displayScaledSizeX, 0, 512, 600); + drawStatInfo(g); + } + + if (game.isPaused()) { + g.drawImage(displayImagePaused, + 0, 0, displayScaledSizeX, displayScaledSizeY, + 0, 0, AppleDisplay.DISPLAY_SIZE_X, AppleDisplay.DISPLAY_SIZE_Y, + MyView.this); + } + + if (game.isGlare()) { + g.drawImage(displayImageGlare, + 0, 0, displayScaledSizeX, displayScaledSizeY, + 0, 0, AppleDisplay.DISPLAY_SIZE_X, AppleDisplay.DISPLAY_SIZE_Y, + MyView.this); + } + } + + /** + * Paint stat info + */ + private void drawStatInfo(Graphics g) { + StringBuffer statInfo = new StringBuffer(); + statInfo.append(game.getStatInfo()).append("\n"); + + StringTokenizer lines = new StringTokenizer(statInfo.toString(), "\n"); + + final int fontSize = 32; + int drawPosY = fontSize; + + g.setColor(Color.white); + + while (lines.hasMoreTokens()) { + String line = lines.nextToken(); + g.drawString(line, displayScaledSizeX, drawPosY); + drawPosY += fontSize; + } + } + }; + + private Image createImage(String name) { +try { + MediaTracker mt = new MediaTracker(this); + + Image image = Toolkit.getDefaultToolkit().getImage(getClass().getResource(name)); + mt.addImage(image, 0); + + try { mt.waitForID(0); } catch (InterruptedException e) {} + + return image; +} catch (Throwable t) { + debug(t); + repaint(); + return null; +} + } + + /* */ + public Object getCharSet(int[] buffer, int w, int h, int s) { + Image charSetSource = createImage("/Character Set.png"); + BufferedImage bi = (BufferedImage) createImage(w, h); + bi.getGraphics().drawImage(charSetSource, 0, 0, null); + + bi.getRGB( + 0, 0, + w, h, + buffer, + 0, s); + + return charSetSource; + } + + /** @see #getCharSet(int[], int, int, int) */ + public void flushCharSet(Object resource) { + ((Image) resource).flush(); + } + + public void setDisplayScaledSizeX(int w) { + gameVC.displayScaledSizeX = w; + } + + public void setDisplayScaledSizeY(int h) { + gameVC.displayScaledSizeY = h; + } + } + + /** */ + class MyDao implements AppleIIGo.Dao { + private String root; + private Properties props = new Properties(); + + MyDao() throws IOException { + root = System.getProperty("bluray.vfs.root", "../tmp"); +//System.err.println("root: " + root); + props.load(new FileInputStream(new File(root, "appleii.properties"))); + } + + /* */ + public String getParameter(String parameter) { + return props.getProperty(parameter); + } + + /* */ + public void read(byte[] bytes, int offset, int length) { + try { + int l = 0; + while (l < length) { + int r = is.read(bytes, offset + l, length - l); + if (r < 0) { +System.err.println("Illegal EOF: " + l + "/" + length); + break; + } + l += r; + } + } catch (IOException e) { +//e.printStackTrace(System.err); + throw new IllegalStateException(e); + } + } + + private InputStream is = null; + + /** + * Open input stream + */ + public void openInputStream(String resource) { + try { +// URL url = getClass().getResource(resource); +// is = url.openStream(); + this.is = new FileInputStream(new File(root, resource)); + + if (resource.toLowerCase().endsWith(".gz")) { + this.is = new GZIPInputStream(is); + } + } catch (IOException e) { +//e.printStackTrace(System.err); + throw new IllegalStateException(e); + } + } + + /** + * Close input stream + */ + public void closeInputStream() { + try { + is.close(); + } catch (IOException e) { +//e.printStackTrace(System.err); + throw new IllegalStateException(e); + } + } + +// private OutputStream os; + + /** + * Open output stream + */ +// public void openOutputStream(String resource) throws IOException { +// if (!(resource.substring(0, 6).equals("http://"))) { +// this.os = new FileOutputStream(resource); +// } +// } + } +} + + +/* */ diff --git a/src/main/java/vavi/apps/appleii/AppleIIGo.java b/src/main/java/vavi/apps/appleii/AppleIIGo.java new file mode 100644 index 0000000..aed78a3 --- /dev/null +++ b/src/main/java/vavi/apps/appleii/AppleIIGo.java @@ -0,0 +1,369 @@ +/* + * AppleIIGo + * The Java Apple II Emulator + * (C) 2006 by Marc S. Ressl(ressl@lonetree.com) + * Released under the GPL + */ + +package vavi.apps.appleii; + + +/** + * AppleIIGo class

+ * Connects EmAppleII, AppleCanvas + */ +public class AppleIIGo { + // Class instances + private EmAppleII apple; + private AppleDisplay display; +// private AppleSpeaker speaker; + private DiskII disk; + + // Machine variables + private boolean isCpuPaused; + private boolean isCpuDebugEnabled; + + /** */ + public boolean isCpuDebugEnabled() { + return isCpuDebugEnabled; + } + + // Keyboard variables + private boolean keyboardUppercaseOnly; + + // Paddle variables + private boolean isPaddleInverted; + + // Disk variables + private String diskDriveResource[] = new String[2]; + + public String getDiskDriveResource(int drive) { + return diskDriveResource[drive]; + } + + private boolean diskWritable; + + /** */ + public interface View { + /** */ + void repaint(); + /** */ + Object getCharSet(int[] buffer, int w, int h, int s); + /** */ + void flushCharSet(Object resource); + /** */ + void setDisplayScaledSizeX(int w); + /** */ + void setDisplayScaledSizeY(int h); + /** */ + void debug(Throwable t); + /** */ + void debug(String s); + } + + /** */ + public void setView(View view) { + this.view = view; + } + + /** */ + private View view; + + /** */ + public interface Dao { + /** */ + String getParameter(String parameter); + /** */ + void openInputStream(String resource); + /** */ + void read(byte[] bytes, int offset, int length); + /** */ + void closeInputStream(); + } + + /** */ + public void setDao(Dao dao) { + this.dao = dao; + } + + /** */ + private Dao dao; + + public void setKeyLatch(int key) { + if (key < 128) { + if (keyboardUppercaseOnly && (key >= 97) && (key <= 122)) { + key -= 32; + } + apple.setKeyLatch(key); + } + } + + public void setButton(int button, boolean flag) { + apple.paddle.setButton(button, flag); + } + + /** for key */ + public void setPaddle(int paddle, int value) { + apple.paddle.setPaddlePos(paddle, value); + } + + /** for mouse */ + public void setPaddlePos(int x, int y) { + if (isPaddleInverted) { + apple.paddle.setPaddlePos(0, (int) (display.getScale() * (255 - y * 256 / 192))); + apple.paddle.setPaddlePos(1, (int) (display.getScale() * (255 - x * 256 / 280))); + } else { + apple.paddle.setPaddlePos(0, (int) (x * display.getScale() * 256 / 280)); + apple.paddle.setPaddlePos(1, (int) (y * display.getScale() * 256 / 192)); + } + } + + public void setVolume(boolean up) { +// speaker.setVolume(speaker.getVolume() + (up ? 1 : -1)); + } + + public void toggleStatMode() { + setStatMode(!isStatMode); + } + + public void toggleStepMode() { + apple.setStepMode(!apple.getStepMode()); + } + + public void stepInstructions(int step) { + apple.setStepMode(apple.getStepMode()); + apple.stepInstructions(step); + } + + public int[] getDisplayImageBuffer() { + return display.getDisplayImageBuffer(); + } + + public boolean isPaused() { + return display.isPaused(); + } + + private boolean isGlare; + private boolean isStatMode; + + /** + * Set glare + */ + public void setGlare(boolean value) { + isGlare = value; + display.requestRefresh(); + } + + /** + * Get glare + */ + public boolean isGlare() { + return isGlare; + } + + /** + * Set stat mode + */ + public void setStatMode(boolean value) { + isStatMode = value; + display.requestRefresh(); + } + + /** + * Get stat mode + */ + public boolean isStatMode() { + return isStatMode; + } + + public String getStatInfo() { + StringBuffer statInfo = new StringBuffer(); + statInfo.append(apple.getStatInfo()).append("\n").append(display.getStatInfo()); + return statInfo.toString(); + } + + /** + * Parameters + */ + private String getParameter(String parameter, String defaultValue) { + String value = dao.getParameter(parameter); + if ((value == null) || (value.length() == 0)) { + return defaultValue; + } + return value; + } + + /** + * On applet initialization + */ + public void init() { +System.err.println("init()"); + + // Activate listeners + + // Initialize Apple II emulator + apple = new EmAppleII(view); + loadRom(getParameter("cpuRom", "")); + apple.setCpuSpeed(new Integer(getParameter("cpuSpeed", "1000")).intValue()); + isCpuPaused = getParameter("cpuPaused", "false").equals("true"); + isCpuDebugEnabled = getParameter("cpuDebugEnabled", "false").equals("true"); + apple.setStepMode(getParameter("cpuStepMode", "false").equals("true")); + + // Keyboard + keyboardUppercaseOnly = getParameter("keyboardUppercaseOnly", "true").equals("true"); + + // Display + display = new AppleDisplay(apple); + display.setScale(new Float(getParameter("displayScale", "1")).floatValue()); + display.setRefreshRate(new Integer(getParameter("displayRefreshRate", "10")).intValue()); + display.setColorMode(new Integer(getParameter("displayColorMode", "0")).intValue()); + setStatMode(getParameter("displayStatMode", "false").equals("true")); + setGlare(getParameter("displayGlare", "false").equals("true")); + + // Speaker +// speaker = new AppleSpeaker(apple); +// speaker.setVolume(new Integer(getAppletParameter("speakerVolume", "3")).intValue()); + + // Peripherals + disk = new DiskII(); + apple.setPeripheral(disk, 6); + + // Initialize disk drives + diskWritable = getParameter("diskWritable", "false").equals("true"); + mountDisk(0, getParameter("diskDrive1", "")); + mountDisk(1, getParameter("diskDrive2", "")); + } + + public void start() { + // Start CPU + if (!isCpuPaused) { + resume(); + } + } + + /** + * On applet destruction + */ + public void destroy() { +System.err.println("destroy()"); + unmountDisk(0); + unmountDisk(1); + } + + /** + * Pause emulator + */ + public void pause() { +System.err.println("pause()"); + isCpuPaused = true; + apple.setPaused(isCpuPaused); + display.setPaused(isCpuPaused); +// speaker.setPaused(isCpuPaused); + } + + /** + * Resume emulator + */ + public void resume() { +System.err.println("resume()"); + isCpuPaused = false; +// speaker.setPaused(isCpuPaused); + display.setPaused(isCpuPaused); + apple.setPaused(isCpuPaused); + } + + /** + * Restarts emulator + */ + public void restart() { +System.err.println("restart()"); + apple.restart(); + } + + /** + * Resets emulator + */ + public void reset() { +System.err.println("reset()"); + apple.reset(); + } + + /** + * Load ROM + */ + public void loadRom(String resource) { +System.err.println("loadRom(resource: " + resource + ")"); + apple.loadRom(dao, resource); + } + + /** + * Mount a disk + */ + public boolean mountDisk(int drive, String resource) { +System.err.println("mountDisk(drive: " + drive + ", resource: " + resource + ")"); + + if ((drive < 0) || (drive > 2)) { + return false; + } + + try { + unmountDisk(drive); + + diskDriveResource[drive] = resource; + +System.err.println("mount: dirve: " + drive + ", " + resource); + disk.readDisk(dao, drive, resource, 254, false); + + return true; + } catch (Throwable e) { +if (e instanceof IllegalStateException) { + System.err.println("mount: drive: " + drive + ": no disk"); +} else { + e.printStackTrace(System.err); +} + return false; + } + } + + /** + * Unmount a disk + */ + public void unmountDisk(int drive) { +System.err.println("unmount: drive: " + drive); + if ((drive < 0) || (drive > 2)) { + return; + } + + if (!diskWritable) { +System.err.println("unmount: drive: " + drive + ", not writable"); + return; + } + + try { + disk.writeDisk(drive, diskDriveResource[drive]); + } catch (Throwable e) { +if (e instanceof NullPointerException) { + System.err.println("unmount: drive: " + drive + ": no disk"); +} else { + e.printStackTrace(System.err); +} + } + } + + /** + * Set color mode + */ + public void setColorMode(int value) { +System.err.println("setColorMode(value: " + value + ")"); + display.setColorMode(value); + } + + /** + * Get disk activity + */ + public boolean getDiskActivity() { + return (!isCpuPaused && disk.isMotorOn()); + } +} + +/* */ diff --git a/src/main/java/vavi/apps/appleii/DiskII.java b/src/main/java/vavi/apps/appleii/DiskII.java new file mode 100644 index 0000000..bf8c3f6 --- /dev/null +++ b/src/main/java/vavi/apps/appleii/DiskII.java @@ -0,0 +1,519 @@ +/* + * AppleIIGo + * Disk II Emulator + * (C) 2006 by Marc S. Ressl(ressl@lonetree.com) + * Released under the GPL + * Based on work by Doug Kwan + */ + +package vavi.apps.appleii; + + +public class DiskII extends Peripheral { + // ROM (with boot wait cycle optimization) + private static final int[] rom = { + 0xa2, 0x20, 0xa0, 0x00, 0xa2, 0x03, 0x86, 0x3c, 0x8a, 0x0a, 0x24, 0x3c, 0xf0, 0x10, 0x05, 0x3c, + 0x49, 0xff, 0x29, 0x7e, 0xb0, 0x08, 0x4a, 0xd0, 0xfb, 0x98, 0x9d, 0x56, 0x03, 0xc8, 0xe8, 0x10, + 0xe5, 0x20, 0x58, 0xff, 0xba, 0xbd, 0x00, 0x01, 0x0a, 0x0a, 0x0a, 0x0a, 0x85, 0x2b, 0xaa, 0xbd, + 0x8e, 0xc0, 0xbd, 0x8c, 0xc0, 0xbd, 0x8a, 0xc0, 0xbd, 0x89, 0xc0, 0xa0, 0x50, 0xbd, 0x80, 0xc0, + 0x98, 0x29, 0x03, 0x0a, 0x05, 0x2b, 0xaa, 0xbd, 0x81, 0xc0, 0xa9, 0x56, 0xa9, 0x00, 0xea, 0x88, + 0x10, 0xeb, 0x85, 0x26, 0x85, 0x3d, 0x85, 0x41, 0xa9, 0x08, 0x85, 0x27, 0x18, 0x08, 0xbd, 0x8c, + 0xc0, 0x10, 0xfb, 0x49, 0xd5, 0xd0, 0xf7, 0xbd, 0x8c, 0xc0, 0x10, 0xfb, 0xc9, 0xaa, 0xd0, 0xf3, + 0xea, 0xbd, 0x8c, 0xc0, 0x10, 0xfb, 0xc9, 0x96, 0xf0, 0x09, 0x28, 0x90, 0xdf, 0x49, 0xad, 0xf0, + 0x25, 0xd0, 0xd9, 0xa0, 0x03, 0x85, 0x40, 0xbd, 0x8c, 0xc0, 0x10, 0xfb, 0x2a, 0x85, 0x3c, 0xbd, + 0x8c, 0xc0, 0x10, 0xfb, 0x25, 0x3c, 0x88, 0xd0, 0xec, 0x28, 0xc5, 0x3d, 0xd0, 0xbe, 0xa5, 0x40, + 0xc5, 0x41, 0xd0, 0xb8, 0xb0, 0xb7, 0xa0, 0x56, 0x84, 0x3c, 0xbc, 0x8c, 0xc0, 0x10, 0xfb, 0x59, + 0xd6, 0x02, 0xa4, 0x3c, 0x88, 0x99, 0x00, 0x03, 0xd0, 0xee, 0x84, 0x3c, 0xbc, 0x8c, 0xc0, 0x10, + 0xfb, 0x59, 0xd6, 0x02, 0xa4, 0x3c, 0x91, 0x26, 0xc8, 0xd0, 0xef, 0xbc, 0x8c, 0xc0, 0x10, 0xfb, + 0x59, 0xd6, 0x02, 0xd0, 0x87, 0xa0, 0x00, 0xa2, 0x56, 0xca, 0x30, 0xfb, 0xb1, 0x26, 0x5e, 0x00, + 0x03, 0x2a, 0x5e, 0x00, 0x03, 0x2a, 0x91, 0x26, 0xc8, 0xd0, 0xee, 0xe6, 0x27, 0xe6, 0x3d, 0xa5, + 0x3d, 0xcd, 0x00, 0x08, 0xa6, 0x2b, 0x90, 0xdb, 0x4c, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + // Constants + private static final int NUM_DRIVES = 2; + private static final int DOS_NUM_SECTORS = 16; + private static final int DOS_NUM_TRACKS = 35; + private static final int DOS_TRACK_BYTES = 256 * DOS_NUM_SECTORS; + private static final int RAW_TRACK_BYTES = 6656; // TODO 6250 ??? + + // Disk II direct access variables + private int drive = 0; + private boolean isMotorOn = false; + + private byte[][][] disk = new byte[NUM_DRIVES][DOS_NUM_TRACKS][]; + private boolean[] isWriteProtected = new boolean[NUM_DRIVES]; + + private int currPhysTrack; + private int currNibble; + + // Caches + private int[] driveCurrPhysTrack = new int[NUM_DRIVES]; + private byte[] realTrack; + + /* + * Disk II emulation: + * + * C0xD, C0xE -> Read write protect + * C0xE, C0xC -> Read data from disk + * Write data to disk -> C0xF, C0xC + * Write data to disk -> C0xD, C0xC + * + * We use 'fast mode', i.e. no 65(C)02 clock reference + * We use simplified track handling (only adjacent phases) + */ + + // Internal registers + private int latchAddress; + private int latchData; + private boolean writeMode; + + // GCR encoding and decoding tables + private static final int[] gcrEncodingTable = { + 0x96, 0x97, 0x9a, 0x9b, 0x9d, 0x9e, 0x9f, 0xa6, + 0xa7, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb2, 0xb3, + 0xb4, 0xb5, 0xb6, 0xb7, 0xb9, 0xba, 0xbb, 0xbc, + 0xbd, 0xbe, 0xbf, 0xcb, 0xcd, 0xce, 0xcf, 0xd3, + 0xd6, 0xd7, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, + 0xdf, 0xe5, 0xe6, 0xe7, 0xe9, 0xea, 0xeb, 0xec, + 0xed, 0xee, 0xef, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, + 0xf7, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, + }; +// private int[] gcrDecodingTable = new int[256]; + private int[] gcrSwapBit = {0, 2, 1, 3}; + private int[] gcrBuffer = new int[256]; + private int[] gcrBuffer2 = new int[86]; + + // Physical sector to DOS 3.3 logical sector table + private static final int[] gcrLogicalSector = { + 0x0, 0x7, 0xe, 0x6, 0xd, 0x5, 0xc, 0x4, + 0xb, 0x3, 0xa, 0x2, 0x9, 0x1, 0x8, 0xf + }; + + // Temporary variables for conversion + private byte[] gcrNibbles = new byte[RAW_TRACK_BYTES]; + private int gcrNibblesPos; + + /** + * Constructor + */ + public DiskII() { + readDisk(null, 0, null, 254, false); + readDisk(null, 1, null, 254, false); + } + + /** + * I/O read + * + * @param address Address + */ + public int ioRead(int address) { + int phase; + + switch (address & 0xf) { + case 0x0: + case 0x2: + case 0x4: + case 0x6: + // Q0, Q1, Q2, Q3 off + break; + case 0x1: + // Q0 on + phase = currPhysTrack & 3; + if (phase == 1) { + if (currPhysTrack > 0) { + currPhysTrack--; + } + } else if (phase == 3) { + if (currPhysTrack < ((2 * DOS_NUM_TRACKS) - 1)) { + currPhysTrack++; + } + } + realTrack = disk[drive][currPhysTrack >> 1]; + break; + case 0x3: + // Q1 on + phase = currPhysTrack & 3; + if (phase == 2) { + if (currPhysTrack > 0) { + currPhysTrack--; + } + } else if (phase == 0) { + if (currPhysTrack < ((2 * DOS_NUM_TRACKS) - 1)) { + currPhysTrack++; + } + } + realTrack = disk[drive][currPhysTrack >> 1]; + break; + case 0x5: + // Q2 on + phase = currPhysTrack & 3; + if (phase == 3) { + if (currPhysTrack > 0) { + currPhysTrack--; + } + } else if (phase == 1) { + if (currPhysTrack < ((2 * DOS_NUM_TRACKS) - 1)) { + currPhysTrack++; + } + } + realTrack = disk[drive][currPhysTrack >> 1]; + break; + case 0x7: + // Q3 on + phase = currPhysTrack & 3; + if (phase == 0) { + if (currPhysTrack > 0) { + currPhysTrack--; + } + } else if (phase == 2) { + if (currPhysTrack < ((2 * DOS_NUM_TRACKS) - 1)) { + currPhysTrack++; + } + } + realTrack = disk[drive][currPhysTrack >> 1]; + break; + case 0x8: + // Motor off + isMotorOn = false; + break; + case 0x9: + // Motor on + isMotorOn = true; + break; + case 0xa: + // Drive 1 + driveCurrPhysTrack[drive] = currPhysTrack; + drive = 0; + currPhysTrack = driveCurrPhysTrack[drive]; + + realTrack = disk[drive][currPhysTrack >> 1]; + break; + case 0xb: + // Drive 2 + driveCurrPhysTrack[drive] = currPhysTrack; + drive = 1; + currPhysTrack = driveCurrPhysTrack[drive]; + + realTrack = disk[drive][currPhysTrack >> 1]; + break; + case 0xc: + return ioLatchC(); + case 0xd: + ioLatchD(0xff); + break; + case 0xe: + return ioLatchE(); + case 0xf: + ioLatchF(0xff); + break; + } + + return rand.nextInt(256); + } + + /** + * I/O write + * + * @param address Address + */ + public void ioWrite(int address, int value) { + switch (address & 0xf) { + case 0x0: + case 0x1: + case 0x2: + case 0x3: + case 0x4: + case 0x5: + case 0x6: + case 0x7: + case 0x8: + case 0x9: + case 0xa: + case 0xb: + ioRead(address); + break; + case 0xc: + ioLatchC(); + break; + case 0xd: + ioLatchD(value); + break; + case 0xe: + ioLatchE(); + break; + case 0xf: + ioLatchF(value); + break; + } + } + + /** + * Memory read + * + * @param address Address + */ + public int memoryRead(int address) { + return rom[address & 0xff]; + } + + /** + * Reset peripheral + */ + public void reset() { + ioRead(0x8); + } + + /** + * Loads a disk + * + * @param resource filename + * @param drive Disk II drive + * @throws IllegalStateException + */ + public void readDisk(AppleIIGo.Dao dao, int drive, String resource, int volume, boolean isWriteProtected) { + byte[] track = new byte[RAW_TRACK_BYTES]; + + boolean isNib = false; + if (resource != null) { + dao.openInputStream(resource); + if (resource.toLowerCase().endsWith(".nib")) { +System.err.println("DRIVE[" + drive + "]: NIB"); + isNib = true; + } else { +System.err.println("DRIVE[" + drive + "]: DSK"); + } + } + for (int trackNum = 0; trackNum < DOS_NUM_TRACKS; trackNum++) { + disk[drive][trackNum] = new byte[RAW_TRACK_BYTES]; + + if (resource != null) { + if (isNib) { + dao.read(disk[drive][trackNum], 0, RAW_TRACK_BYTES); + } else { + dao.read(track, 0, DOS_TRACK_BYTES); + trackToNibbles(track, disk[drive][trackNum], volume, trackNum); + } + } + } + if (resource != null) { + dao.closeInputStream(); + } + + this.realTrack = disk[drive][currPhysTrack >> 1]; + this.isWriteProtected[drive] = isWriteProtected; + } + + /** + * Writes a disk + * + * @param resource filename + * @param drive Disk II drive + */ + public void writeDisk(int drive, String resource) { + } + + /** + * Motor on indicator + */ + public boolean isMotorOn() { + return isMotorOn; + } + + /** + * I/O read Latch C + * + * @param address Address + */ + private int ioLatchC() { + if (writeMode) { + // Write data: C0xD, C0xC + realTrack[currNibble] = (byte) latchData; + } else { + // Read data: C0xE, C0xC + latchData = (realTrack[currNibble] & 0xff); + } + + currNibble++; + if (currNibble >= RAW_TRACK_BYTES) { + currNibble = 0; + } + + latchAddress = 0xc; + return latchData; + } + + /** + * I/O write Latch D + * + * @param address Address + */ + private void ioLatchD(int value) { + // Prepare write + writeMode = true; + latchData = value; + latchAddress = 0xd; + } + + /** + * I/O read Latch E + * + * @param address Address + */ + private int ioLatchE() { + // Read write-protect: C0xD, C0xE + if (latchAddress == 0xd) { + latchAddress = 0xe; + return isWriteProtected[drive] ? 0x80 : 0x00; + } + + writeMode = false; + latchAddress = 0xe; + return 0x3c; + } + + /** + * I/O write Latch F + * + * @param address Address + */ + private void ioLatchF(int value) { + // Prepare write + writeMode = true; + latchData = value; + latchAddress = 0xf; + } + + /* + * TRACK CONVERSION ROUTINES + */ + + /** + * Writes a nibble + * + * @param value Value + */ + private final void gcrWriteNibble(int value) { + gcrNibbles[gcrNibblesPos] = (byte) value; + gcrNibblesPos++; + } + + /** + * Writes sync bits + * + * @param length Number of bits + */ + private final void writeSync(int length) { + while(length > 0) { + length--; + gcrWriteNibble(0xff); + } + } + + /** + * Write an FM encoded value, used in writing address fields + * + * @param value Value + */ + private final void encode44(int value) { + gcrWriteNibble((value >> 1) | 0xaa); + gcrWriteNibble(value | 0xaa); + } + + /** + * Encode in 6:2 + * + * @param track Sectorized track data + * @param offset Offset in this data + */ + private void encode62(byte[] track, int offset) { + // 86 * 3 = 258, so the first two byte are encoded twice + gcrBuffer2[0] = gcrSwapBit[track[offset + 1] & 0x03]; + gcrBuffer2[1] = gcrSwapBit[track[offset] & 0x03]; + + // Save higher 6 bits in gcrBuffer and lower 2 bits in gcrBuffer2 + for(int i = 255, j = 2; i >= 0; i--, j = j == 85 ? 0: j + 1) { + gcrBuffer2[j] = ((gcrBuffer2[j] << 2) | gcrSwapBit[track[offset + i] & 0x03]); + gcrBuffer[i] = (track[offset + i] & 0xff) >> 2; + } + + // Clear off higher 2 bits of GCR_buffer2 set in the last call + for(int i = 0; i < 86; i++) { + gcrBuffer2[i] &= 0x3f; + } + } + + /** + * Write address field + * + * @param track Sectorized track data + * @param offset Offset in this data + */ + private final void writeAddressField(int volumeNum, int trackNum, int sectorNum) { + // Write address mark + gcrWriteNibble(0xd5); + gcrWriteNibble(0xaa); + gcrWriteNibble(0x96); + + // Write volume, trackNum, sector & checksum + encode44(volumeNum); + encode44(trackNum); + encode44(sectorNum); + encode44(volumeNum ^ trackNum ^ sectorNum); + + // Write epilogue + gcrWriteNibble(0xde); + gcrWriteNibble(0xaa); + gcrWriteNibble(0xeb); + } + + /** + * Write data field + */ + private void writeDataField() { + int last = 0; + int checksum; + + // Write prologue + gcrWriteNibble(0xd5); + gcrWriteNibble(0xaa); + gcrWriteNibble(0xad); + + // Write GCR encoded data + for (int i = 0x55; i >= 0; i--) { + checksum = last ^ gcrBuffer2[i]; + gcrWriteNibble(gcrEncodingTable[checksum]); + last = gcrBuffer2[i]; + } + for (int i = 0; i < 256; i++) { + checksum = last ^ gcrBuffer[i]; + gcrWriteNibble(gcrEncodingTable[checksum]); + last = gcrBuffer[i]; + } + + // Write checksum + gcrWriteNibble(gcrEncodingTable[last]); + + // Write epilogue + gcrWriteNibble(0xde); + gcrWriteNibble(0xaa); + gcrWriteNibble(0xeb); + } + + /** + * Converts a track to nibbles + */ + private void trackToNibbles(byte[] track, byte[] nibbles, int volumeNum, int trackNum) { + this.gcrNibbles = nibbles; + gcrNibblesPos = 0; + + for (int sectorNum = 0; sectorNum < DOS_NUM_SECTORS; sectorNum++) { + encode62(track, gcrLogicalSector[sectorNum] << 8); + writeSync(12); + writeAddressField(volumeNum, trackNum, sectorNum); + writeSync(8); + writeDataField(); + } + writeSync(RAW_TRACK_BYTES - gcrNibblesPos); + } +} diff --git a/src/main/java/vavi/apps/appleii/Em6502.java b/src/main/java/vavi/apps/appleii/Em6502.java new file mode 100644 index 0000000..e66170f --- /dev/null +++ b/src/main/java/vavi/apps/appleii/Em6502.java @@ -0,0 +1,1648 @@ +/* + * AppleIIGo + * Apple II Emulator for J2SE + * (C) 2006 by Marc S. Ressl(ressl@lonetree.com) + * Released under the GPL + * Adapted from code by Doug Kwan + * Adapted from code by Randy Frank randy@tessa.iaf.uiowa.edu + * Adapted from code (C) 1989 Ben Koning [556498717 408/738-1763 ben@apple.com] + */ + +package vavi.apps.appleii; + + +public class Em6502 { + /** + * Base memory (including zero page and stack) + */ + public byte[] mem = null; + + /** + * Generic memory read & write (0x0000-0xffff) + */ + protected int memoryRead(int addr) { + return mem[addr] & 0xff; + } + + protected void memoryWrite(int addr, int value) { + mem[addr] = (byte) value; + } + + /* + * Zero page read & write + */ + private final int zeroPageRead(int addr) { + return mem[addr] & 0xff; + } + + private final void zeroPageWrite(int addr, int value) { + mem[addr] = (byte) value; + } + + /* + * Userspace interrupts + */ + public final void assertReset() { + exceptionRegister |= SIG_6502_RESET; + } + + public final void assertNMI() { + exceptionRegister |= SIG_6502_NMI; + } + + public final void assertIRQ() { + exceptionRegister |= SIG_6502_IRQ; + } + + /* + * Userspace interrupt handlers + */ + protected void onReset() { + } + + protected void onNMI() { + } + + protected void onIRQ() { + } + + /** + * CPU Registers + */ + public int A, X, Y, P, S, PC; + + /** + * CPU Clock + */ + protected int clock; + + /* + * CPU Flags + */ + public static final int FLAG_C = (1 << 0); + public static final int FLAG_Z = (1 << 1); + public static final int FLAG_I = (1 << 2); + public static final int FLAG_D = (1 << 3); + public static final int FLAG_B = (1 << 4); + public static final int FLAG_V = (1 << 6); + public static final int FLAG_N = (1 << 7); + /* + * owing to a bug in 6502, the bit 5 must be always 1; + * otherwise, programs like DOS 3.3 will break down + * see instructions in $9FF4-$9FF5 of DOS 3.3 + */ + + /* + * CPU Signals + */ + private int exceptionRegister = 0; + + public static final int SIG_6502_RESET = (1 << 0); + public static final int SIG_6502_NMI = (1 << 1); + public static final int SIG_6502_IRQ = (1 << 2); + + /** + * CPU IRQ State + */ + private int pendingIRQ; + + /* + * Emulator registers + */ + private int easp1, easp2; + private int operandAddress; + private int opcode; + private int operand; + private int result; + private int NZFlags; + + /* + * ALU look up tables + */ + private int BCDTableAdd[]; // addition correction + private int BCDTableSub[]; // subtraction correction + + /** + * Constructor + */ + public Em6502() { + // Init BCD tables + BCDTableAdd = new int[512]; + BCDTableSub = new int[512]; + + for (int i = 0; i < 512; i++) { + BCDTableAdd[i] = ((i & 0x0f) <= 0x09) ? i : (i + 0x06); + BCDTableAdd[i] += ((BCDTableAdd[i] & 0xf0) <= 0x90) ? 0 : 0x60; + if (BCDTableAdd[i] > 0x1ff) { + BCDTableAdd[i] -= 0x100; + } + + BCDTableSub[i] = ((i & 0x0f) <= 0x09) ? i : (i - 0x06); + BCDTableSub[i] -= ((BCDTableSub[i] & 0xf0) <= 0x90) ? 0 : 0x60; + } + } + + /* + * Stack macros + */ + private final int pop() { + S++; + S &= 0xff; + return (mem[S | 0x100] & 0xff); + } + + private final void push(int value) { + mem[S | 0x100] = (byte) value; + S--; + S &= 0xff; + } + + /* + * Macros for P flags + */ + private final void setN(boolean b) {if (b) P |= FLAG_N; else P &= ~FLAG_N;} + private final void setV(boolean b) {if (b) P |= FLAG_V; else P &= ~FLAG_V;} + private final void setB(boolean b) {if (b) P |= FLAG_B; else P &= ~FLAG_B;} + private final void setD(boolean b) {if (b) P |= FLAG_D; else P &= ~FLAG_D;} + private final void setI(boolean b) {if (b) P |= FLAG_I; else P &= ~FLAG_I;} + private final void setZ(boolean b) {if (b) P |= FLAG_Z; else P &= ~FLAG_Z;} + private final void setC(boolean b) {if (b) P |= FLAG_C; else P &= ~FLAG_C;} + private final boolean getN() {return ((P & FLAG_N) != 0);} + private final boolean getV() {return ((P & FLAG_V) != 0);} + private final boolean getB() {return ((P & FLAG_B) != 0);} + private final boolean getD() {return ((P & FLAG_D) != 0);} + private final boolean getI() {return ((P & FLAG_I) != 0);} + private final boolean getZ() {return ((P & FLAG_Z) != 0);} + private final boolean getC() {return ((P & FLAG_C) != 0);} + + /* + * Fast condition codes. Instead of using bits to encode condition codes, + * recent ALU results are cached to that the condition codes can be + * handled more easily by the emulator's native hardware. + */ + private final boolean getFN() {return ((NZFlags & 0x280) != 0);} + private final boolean getFNotN() {return ((NZFlags & 0x280) == 0);} + private final boolean getFZ() {return ((NZFlags & 0xff) == 0);} + private final boolean getFNotZ() {return ((NZFlags & 0xff) != 0);} + private final void setFNZ(boolean n, boolean z) {NZFlags = ((n) ? 0x200 : 0x00) | ((z) ? 0x00 : 0x01);} + private final boolean getFC() {return (result >> 8) != 0;} + private final boolean getFNotC() {return (result >> 8) == 0;} + private final int getFC_() {return result >> 8;} + private final void setFC(boolean c) {result = (c ? 0x100 : 0x00);} + + /** + * Macro for page crossing cycle regulation + */ + private final void checkCrossPage(int addr, int offset) { + if ((((addr + offset) ^ addr) & 0xff00) != 0) { + clock++; + } + } + + /* + * Macros for effective address calculation + * (Macros whose names end with NC do not check for page crossing) + */ + private final int eaimm() { + easp1 = memoryRead(PC); PC++; return easp1; + } + + private final int eazp() { + easp1 = memoryRead(PC); PC++; return easp1; + } + + private final int eazpx() { + easp1 = (memoryRead(PC) + X) & 0xff; PC++; return easp1; + } + + private final int eazpy() { + easp1 = (memoryRead(PC) + Y) & 0xff; PC++; return easp1; + } + + private final int eaabs() { + easp1 = memoryRead(PC); PC++; + easp1 += (memoryRead(PC) << 8); PC++; + return easp1; + } + + private final int earel() { +// easp1 = memoryRead(PC); PC++; +// return ((easp1 & 0x80) != 0) ? easp1 - 256 : easp1; + easp1 = (byte) memoryRead(PC); PC++; return easp1; + } + + private final int eaabsx() { + // No cross page check... + // easp1 = eaabs(); + // checkCrossPage(easp1, X); + // return easp1 + X; + return eaabs() + X; + } + + private final int eaabsxNC() { + return eaabs() + X; + } + + private final int eaabsy() { + // No cross page check... + // easp1 = eaabs(); + // checkCrossPage(easp1, Y); + // return easp1 + Y; + return eaabs() + Y; + } + + private final int eaabsyNC() { + return eaabs() + Y; + } + + /* + * Indirect addressing + */ + private final int eaabsind() { + easp1 = eaabs(); + easp2 = memoryRead(easp1); + return easp2 + (memoryRead(easp1 + 1) << 8); + } + + private final int eazpxind() { + easp1 = eazpx(); + easp2 = zeroPageRead(easp1); + return easp2 + (zeroPageRead((easp1 + 1) & 0xff) << 8); + } + + private final int eazpindy() { + easp1 = eaimm(); + easp2 = zeroPageRead(easp1); + // No cross page check... + // easp2 += (zeroPageRead((easp1 + 1) & 0xff) << 8); + // checkCrossPage(easp2,Y); + // return easp2 + Y; + return easp2 + (zeroPageRead((easp1 + 1) & 0xff) << 8) + Y; + } + + private final int eazpindyNC() { + easp1 = eaimm(); + easp2 = zeroPageRead(easp1); + return easp2 + (zeroPageRead((easp1 + 1) & 0xff) << 8) + Y; + } + + /* + * New 65C02 addressing mode + */ + private final int eazpind() { + easp1 = eazp(); + easp2 = zeroPageRead(easp1); + return easp2 + (zeroPageRead((easp1 + 1) & 0xff) << 8); + } + + private final int eaabsxind() { + easp1 = eaabs(); + easp2 = memoryRead(easp1); + return easp2 + (memoryRead(easp1 + 1) << 8) + X; + } + + /* + * Misc. macros + */ + private final void adcBCDAdjust() { + if (getD()) result = BCDTableAdd[result]; + } + + private final void sbcBCDAdjust() { + if (getD()) result = BCDTableSub[result]; + } + + private final void branch(int operand) { + // No cross page check... + // checkCrossPage(PC, operand); + PC += operand; + clock++; + } + + /** This executes a single instruction. */ + private final void executeInstruction() { + opcode = memoryRead(PC); + PC++; + + switch(opcode) { + case 0x69: // ADC #imm + operand = eaimm(); + result = operand + A + getFC_(); + setV(!(((operand ^ A) & 0x80) != 0) && (((A ^ result) & 0x80) != 0)); + adcBCDAdjust(); + A = result & 0xff; + NZFlags = A; + clock += 2; + break; + + case 0x6D: // ADC abs + operand = memoryRead(eaabs()); + result = operand + A + getFC_(); + setV(!(((operand ^ A) & 0x80) != 0) && (((A ^ result) & 0x80) != 0)); + adcBCDAdjust(); + A = result & 0xff; + NZFlags = A; + clock += 4; + break; + + case 0x65: // ADC zp + operand = zeroPageRead(eazp()); + result = operand + A + getFC_(); + setV(!(((operand ^ A) & 0x80) != 0) && (((A ^ result) & 0x80) != 0)); + adcBCDAdjust(); + A = result & 0xff; + NZFlags = A; + clock += 3; + break; + + case 0x61: // ADC (zp,X) + operand = memoryRead(eazpxind()); + result = operand + A + getFC_(); + setV(!(((operand ^ A) & 0x80) != 0) && (((A ^ result) & 0x80) != 0)); + adcBCDAdjust(); + A = result & 0xff; + NZFlags = A; + clock += 6; + break; + + case 0x71: // ADC (zp),Y + operandAddress = eazpindy(); + operand = memoryRead(operandAddress); + result = operand + A + getFC_(); + setV(!(((operand ^ A) & 0x80) != 0) && (((A ^ result) & 0x80) != 0)); + adcBCDAdjust(); + A = result & 0xff; + NZFlags = A; + clock += 5; + break; + + case 0x75: // ADC zp,X + operandAddress = eazpx(); + operand = zeroPageRead(operandAddress); + result = operand + A + getFC_(); + setV(!(((operand ^ A) & 0x80) != 0) && (((A ^ result) & 0x80) != 0)); + adcBCDAdjust(); + A = result & 0xff; + NZFlags = A; + clock += 4; + break; + + case 0x7D: // ADC abs,X + operand = memoryRead(eaabsx()); + result = operand + A + getFC_(); + setV(!(((operand ^ A) & 0x80) != 0) && (((A ^ result) & 0x80) != 0)); + adcBCDAdjust(); + A = result & 0xff; + NZFlags = A; + clock += 4; + break; + + case 0x79: // ADC abs,Y + operand = memoryRead(eaabsy()); + result = operand + A + getFC_(); + setV(!(((operand ^ A) & 0x80) != 0) && (((A ^ result) & 0x80) != 0)); + adcBCDAdjust(); + A = result & 0xff; + NZFlags = A; + clock += 4; + break; + + case 0x29: // AND #imm + A &= eaimm(); + NZFlags = A; + clock += 2; + break; + + case 0x2D: // AND abs + A &= memoryRead(eaabs()); + NZFlags = A; + clock += 4; + break; + + case 0x25: // AND zp + A &= zeroPageRead(eazp()); + NZFlags = A; + clock += 3; + break; + + case 0x21: // AND (zp,X) + A &= memoryRead(eazpxind()); + NZFlags = A; + clock += 6; + break; + + case 0x31: // AND (zp),Y + A &= memoryRead(eazpindy()); + NZFlags = A; + clock += 5; + break; + + case 0x35: // AND zp,X + A &= zeroPageRead(eazpx()); + NZFlags = A; + clock += 4; + break; + + case 0x3D: // AND abs,X + A &= memoryRead(eaabsx()); + NZFlags = A; + clock += 4; + break; + + case 0x39: // AND abs,Y + A &= memoryRead(eaabsy()); + NZFlags = A; + clock += 4; + break; + + case 0x0E: // ASL abs + operandAddress = eaabs(); + operand = memoryRead(operandAddress); + result = operand << 1; + NZFlags = result; + memoryWrite(operandAddress, result); + clock += 6; + break; + + case 0x06: // ASL zp + operandAddress = eazp(); + operand = zeroPageRead(operandAddress); + result = operand << 1; + NZFlags = result; + zeroPageWrite(operandAddress, result); + clock += 5; + break; + + case 0x0A: // ASL acc + result = A << 1; + A = result & 0xff; + NZFlags = A; + clock += 2; + break; + + case 0x16: // ASL zp,X + operandAddress = eazpx(); + operand = zeroPageRead(operandAddress); + result = operand << 1; + NZFlags = result; + zeroPageWrite(operandAddress, result); + clock += 6; + break; + + case 0x1E: // ASL abs,X + operandAddress = eaabsx(); + operand = memoryRead(operandAddress); + result = operand << 1; + NZFlags = result; + memoryWrite(operandAddress, result); + clock += 7; + break; + + case 0x90: // BCC rr + operand = earel(); + clock += 2; + if (getFNotC()) + branch(operand); + break; + + case 0xB0: // BCS rr + operand = earel(); + clock += 2; + if (getFC()) + branch(operand); + break; + + case 0xF0: // BEQ rr + operand = earel(); + clock += 2; + if (getFZ()) + branch(operand); + break; + + case 0x2C: // BIT abs + operand = memoryRead(eaabs()); + setV((operand & 0x40) != 0); + NZFlags = ((operand & 0x80) << 2) | (A & operand); + clock += 4; + break; + + case 0x24: // BIT zp + operand = zeroPageRead(eazp()); + setV((operand & 0x40) != 0); + NZFlags = ((operand & 0x80) << 2) | (A & operand); + clock += 3; + break; + + case 0x30: // BMI rr + operand = earel(); + clock += 2; + if (getFN()) { + branch(operand); + } + break; + + case 0xD0: // BNE rr + operand = earel(); + clock += 2; + if (getFNotZ()) { + branch(operand); + } + break; + + case 0x10: // BPL rr + operand = earel(); + clock += 2; + if (getFNotN()) { + branch(operand); + } + break; + + case 0x00: // BRK + push(PC >> 8); // save PCH, PCL & P + push(PC); + setN(getFN()); + setZ(getFZ()); + setC(getFC()); + setB(true); + push(P); + setI(true); + PC = memoryRead(0xfffe); + PC |= memoryRead(0xffff) << 8; + clock += 7; + break; + + case 0x50: // BVC rr + operand = earel(); + clock += 2; + if (!getV()) { + branch(operand); + } + break; + + case 0x70: // BVS rr + operand = earel(); + clock += 2; + if (getV()) { + branch(operand); + } + break; + + case 0x18: // CLC rr + setFC(false); + clock += 2; + break; + + case 0xD8: // CLD + setD(false); + clock += 2; + break; + + case 0x58: // CLI + setI(false); + clock += 2; + if (pendingIRQ > 0) { + pendingIRQ--; + assertIRQ(); + } + break; + + case 0xB8: // CLV + setV(false); + clock += 2; + break; + + case 0xC9: // CMP #imm + result = 0x100 + A - eaimm(); + NZFlags = result; + clock += 2; + break; + + case 0xCD: // CMP abs + result = 0x100 + A - memoryRead(eaabs()); + NZFlags = result; + clock += 4; + break; + + case 0xC5: // CMP zp + result = 0x100 + A - zeroPageRead(eazp()); + NZFlags = result; + clock += 3; + break; + + case 0xC1: // CMP (zp,X) + result = 0x100 + A - memoryRead(eazpxind()); + NZFlags = result; + clock += 6; + break; + + case 0xD1: // CMP (zp),Y + result = 0x100 + A - memoryRead(eazpindy()); + NZFlags = result; + clock += 5; + break; + + case 0xD5: // CMP zp,X + result = 0x100 + A - zeroPageRead(eazpx()); + NZFlags = result; + clock += 4; + break; + + case 0xDD: // CMP abs,X + result = 0x100 + A - memoryRead(eaabsx()); + NZFlags = result; + clock += 4; + break; + + case 0xD9: // CMP abs,Y + result = 0x100 + A - memoryRead(eaabsy()); + NZFlags = result; + clock += 4; + break; + + case 0xE0: // CPX #imm + result = 0x100 + X - eaimm(); + NZFlags = result; + clock += 2; + break; + + case 0xEC: // CPX abs + result = 0x100 + X - memoryRead(eaabs()); + NZFlags = result; + clock += 4; + break; + + case 0xE4: // CPX zp + result = 0x100 + X - zeroPageRead(eazp()); + NZFlags = result; + clock += 3; + break; + + case 0xC0: // CPY #imm + result = 0x100 + Y - eaimm(); + NZFlags = result; + clock += 2; + break; + + case 0xCC: // CPY abs + result = 0x100 + Y - memoryRead(eaabs()); + NZFlags = result; + clock += 4; + break; + + case 0xC4: // CPY zp + result = 0x100+ Y - zeroPageRead(eazp()); + NZFlags = result; + clock += 3; + break; + + case 0xCE: // DEC abs + operandAddress = eaabs(); + operand = memoryRead(operandAddress); + NZFlags = operand + 0xff; + memoryWrite(operandAddress, NZFlags); + clock += 6; + break; + + case 0xC6: // DEC zp + operandAddress = eazp(); + operand = zeroPageRead(operandAddress); + NZFlags = operand + 0xff; + zeroPageWrite(operandAddress, NZFlags); + clock += 5; + break; + + case 0xD6: // DEC zp,X + operandAddress = eazpx(); + operand = zeroPageRead(operandAddress); + NZFlags = operand + 0xff; + zeroPageWrite(operandAddress, NZFlags); + clock += 6; + break; + + case 0xDE: // DEC abs,X + operandAddress = eaabsx(); + operand = memoryRead(operandAddress); + NZFlags = operand + 0xff; + memoryWrite(operandAddress, NZFlags); + clock += 7; + break; + + case 0xCA: // DEX + NZFlags = X + 0xff; + X = NZFlags & 0xff; + clock += 2; + break; + + case 0x88: // DEY + NZFlags = Y + 0xff; + Y = NZFlags & 0xff; + clock += 2; + break; + + case 0x49: // EOR #imm + A ^= eaimm(); + NZFlags = A; + clock += 2; + break; + + case 0x4D: // EOR abs + A ^= memoryRead(eaabs()); + NZFlags = A; + clock += 4; + break; + + case 0x45: // EOR zp + A ^= zeroPageRead(eazp()); + NZFlags = A; + clock += 3; + break; + + case 0x41: // EOR (zp,X) + A ^= memoryRead(eazpxind()); + NZFlags = A; + clock += 6; + break; + + case 0x51: // EOR (zp),Y + A ^= memoryRead(eazpindy()); + NZFlags = A; + clock += 5; + break; + + case 0x55: // EOR zp,X + A ^= zeroPageRead(eazpx()); + NZFlags = A; + clock += 4; + break; + + case 0x5D: // EOR abs,X + A ^= memoryRead(eaabsx()); + NZFlags = A; + clock += 4; + break; + + case 0x59: // EOR abs,Y + A ^= memoryRead(eaabsy()); + NZFlags = A; + clock += 4; + break; + + case 0xEE: // INC abs + operandAddress = eaabs(); + operand = memoryRead(operandAddress); + NZFlags = operand + 1; + memoryWrite(operandAddress, NZFlags); + clock += 6; + break; + + case 0xE6: // INC zp + operandAddress = eazp(); + operand = zeroPageRead(operandAddress); + NZFlags = operand + 1; + zeroPageWrite(operandAddress, NZFlags); + clock += 5; + break; + + case 0xF6: // INC zp,X + operandAddress = eazpx(); + operand = zeroPageRead(operandAddress); + NZFlags = operand + 1; + zeroPageWrite(operandAddress, NZFlags); + clock += 6; + break; + + case 0xFE: // INC abs,X + operandAddress = eaabsxNC(); + operand = memoryRead(operandAddress); + NZFlags = operand + 1; + memoryWrite(operandAddress, NZFlags); + clock += 7; + break; + + case 0xE8: // INX + NZFlags = X + 1; + X = NZFlags & 0xff; + clock += 2; + break; + + case 0xC8: // INY + NZFlags = Y + 1; + Y = NZFlags & 0xff; + clock += 2; + break; + + case 0x4C: // JMP abs + PC = eaabs(); + clock += 3; + break; + + case 0x6C: // JMP (abs) + PC = eaabsind(); + clock += 5; + break; + + case 0x20: // JSR abs + operandAddress = eaabs(); + PC--; + push(PC >> 8); + push(PC); + PC = operandAddress; + clock += 6; + break; + + case 0xA9: // LDA #imm + A = eaimm(); + NZFlags = A; + clock += 2; + break; + + case 0xAD: // LDA abs + A = memoryRead(eaabs()); + NZFlags = A; + clock += 4; + break; + + case 0xA5: // LDA zp + A = zeroPageRead(eazp()); + NZFlags = A; + clock += 3; + break; + + case 0xA1: // LDA (zp,X) + A = memoryRead(eazpxind()); + NZFlags = A; + clock += 6; + break; + + case 0xB1: // LDA (zp),Y + A = memoryRead(eazpindy()); + NZFlags = A; + clock += 5; + break; + + case 0xB5: // LDA zp,X + A = zeroPageRead(eazpx()); + NZFlags = A; + clock += 4; + break; + + case 0xBD: // LDA abs,X + A = memoryRead(eaabsx()); + NZFlags = A; + clock += 4; + break; + + case 0xB9: // LDA abs,Y + A = memoryRead(eaabsy()); + NZFlags = A; + clock += 4; + break; + + case 0xA2: // LDX #imm + X = eaimm(); + NZFlags = X; + clock += 2; + break; + + case 0xAE: // LDX abs + X = memoryRead(eaabs()); + NZFlags = X; + clock += 4; + break; + + case 0xA6: // LDX zp + X = zeroPageRead(eazp()); + NZFlags = X; + clock += 3; + break; + + case 0xBE: // LDX abs,Y + X = memoryRead(eaabsy()); + NZFlags = X; + clock += 4; + break; + + case 0xB6: // LDX zp,Y + X = zeroPageRead(eazpy()); + NZFlags = X; + clock += 4; + break; + + case 0xA0: // LDY #imm + Y = eaimm(); + NZFlags = Y; + clock += 2; + break; + + case 0xAC: // LDY abs + Y = memoryRead(eaabs()); + NZFlags = Y; + clock += 4; + break; + + case 0xA4: // LDY zp + Y = zeroPageRead(eazp()); + NZFlags = Y; + clock += 3; + break; + + case 0xB4: // LDY zp,X + Y = zeroPageRead(eazpx()); + NZFlags = Y; + clock += 4; + break; + + case 0xBC: // LDY abs,X + Y = memoryRead(eaabsx()); + NZFlags = Y; + clock += 4; + break; + + case 0x4E: // LSR abs + operandAddress = eaabs(); + operand = memoryRead(operandAddress); + result = (operand & 0x01) << 8; // just get the C bit + NZFlags = operand >> 1; // result in NZFlags + memoryWrite(operandAddress, NZFlags); + clock += 6; + break; + + case 0x46: // LSR zp + operandAddress = eazp(); + operand = zeroPageRead(operandAddress); + result = (operand & 0x01) << 8; // just get the C bit + NZFlags = operand >> 1; // result in NZFlags + zeroPageWrite(operandAddress, NZFlags); + clock += 5; + break; + + case 0x4A: // LSR acc + result = (A & 0x01) << 8; // just get the C bit + A >>= 1; + NZFlags = A; + clock += 2; + break; + + case 0x56: // LSR zp,X + operandAddress = eazpx(); + operand = zeroPageRead(operandAddress); + result = (operand & 0x01) << 8; // just get the C bit + NZFlags = operand >> 1; // result in NZFlags + zeroPageWrite(operandAddress, NZFlags); + clock += 6; + break; + + case 0x5E: // LSR abs,X + operandAddress = eaabsx(); + operand = memoryRead(operandAddress); + result = (operand & 0x01) << 8; // just get the C bit + NZFlags = operand >> 1; // result in NZFlags + memoryWrite(operandAddress, NZFlags); + clock += 7; + break; + + case 0xEA: // NOP + clock += 2; + break; + + case 0x09: // ORA #imm + A |= eaimm(); + NZFlags = A; + clock += 2; + break; + + case 0x0D: // ORA abs + A |= memoryRead(eaabs()); + NZFlags = A; + clock += 4; + break; + + case 0x05: // ORA zp + A |= zeroPageRead(eazp()); + NZFlags = A; + clock += 3; + break; + + case 0x01: // ORA (zp,X) + A |= memoryRead(eazpxind()); + NZFlags = A; + clock += 6; + break; + + case 0x11: // ORA (zp),Y + A |= memoryRead(eazpindy()); + NZFlags = A; + clock += 5; + break; + + case 0x15: // ORA zp,X + A |= zeroPageRead(eazpx()); + NZFlags = A; + clock += 4; + break; + + case 0x1D: // ORA abs,X + A |= memoryRead(eaabsx()); + NZFlags = A; + clock += 4; + break; + + case 0x19: // ORA abs,Y + A |= memoryRead(eaabsy()); + NZFlags = A; + clock += 4; + break; + + case 0x48: // PHA + push(A); + clock += 3; + break; + + case 0x08: // PHP + setN(getFN()); + setZ(getFZ()); + setC(getFC()); + push(P); + clock += 3; + break; + + case 0x68: // PLA + A = pop(); + NZFlags = A; + clock += 4; + break; + + case 0x28: // PLP + P = pop() | 0x20; // fix bug in bit5 of P + setFC(getC()); + setFNZ(getN(), getZ()); + clock += 4; + if ((pendingIRQ > 0) && !getI()) { + pendingIRQ--; + assertIRQ(); + } + break; + + case 0x2E: // ROL abs + operandAddress = eaabs(); + operand = memoryRead(operandAddress); + result = (operand << 1) | getFC_(); + NZFlags = result; + memoryWrite(operandAddress, result); + clock += 6; + break; + + case 0x26: // ROL zp + operandAddress = eazp(); + operand = zeroPageRead(operandAddress); + result = (operand << 1) | getFC_(); + NZFlags = result; + zeroPageWrite(operandAddress, result); + clock += 5; + break; + + case 0x2A: // ROL acc + result = (A << 1) | getFC_(); + A = result & 0xff; + NZFlags = A; + clock += 2; + break; + + case 0x36: // ROL zp,X + operandAddress = eazpx(); + operand = zeroPageRead(operandAddress); + result = (operand << 1) | getFC_(); + NZFlags = result; + zeroPageWrite(operandAddress, result); + clock += 6; + break; + + case 0x3E: // ROL abs,X + operandAddress = eaabsx(); + operand = memoryRead(operandAddress); + result = (operand << 1) | getFC_(); + NZFlags = result; + memoryWrite(operandAddress, result); + clock += 7; + break; + + case 0x6E: // ROR abs + operandAddress = eaabs(); + operand = memoryRead(operandAddress); + result = ((operand & 0x01) << 8) | (getFC_() << 7) | + (operand >> 1); + NZFlags = result; + memoryWrite(operandAddress, result); + clock += 6; + break; + + case 0x66: // ROR zp + operandAddress = eazp(); + operand = zeroPageRead(operandAddress); + result = ((operand & 0x01) << 8) | (getFC_() << 7) | + (operand >> 1); + NZFlags = result; + zeroPageWrite(operandAddress, result); + clock += 5; + break; + + case 0x6A: // ROR acc + result = ((A & 0x01) << 8) | (getFC_() << 7) | (A >> 1); + A = result & 0xff; + NZFlags = A; + clock += 2; + break; + + case 0x76: // ROR zp,X + operandAddress = eazpx(); + operand = zeroPageRead(operandAddress); + result = ((operand & 0x01) << 8) | (getFC_() << 7) | + (operand >> 1); + NZFlags = result; + zeroPageWrite(operandAddress, result); + clock += 6; + break; + + case 0x7E: // ROR abs,X + operandAddress = eaabsx(); + operand = memoryRead(operandAddress); + result = ((operand & 0x01) << 8) | (getFC_() << 7) | + (operand >> 1); + NZFlags = result; + memoryWrite(operandAddress, result); + clock += 7; + break; + + case 0x40: // RTI + P = pop() | 0x20; // bit 5 bug of 6502 + setFC(getC()); + setFNZ(getN(), getZ()); + PC = pop(); // splitting is necessary + PC += pop() << 8; // because of nested macros + clock += 6; + break; + + case 0x60: // RTS + PC = pop(); // splitting is necessary + PC += pop() << 8; // because of nested macros + PC++; + clock += 6; + break; + + case 0xE9: // SBC #imm + operand = 255 - eaimm(); + result = operand + A + getFC_(); + setV(!(((operand ^ A) & 0x80) != 0) && (((A ^ result) & 0x80) != 0)); + sbcBCDAdjust(); + A = result & 0xff; + NZFlags = A; + clock += 2; + break; + + case 0xED: // SBC abs + operand = 255 - memoryRead(eaabs()); + result = operand + A + getFC_(); + setV(!(((operand ^ A) & 0x80) != 0) && (((A ^ result) & 0x80) != 0)); + sbcBCDAdjust(); + A = result & 0xff; + NZFlags = A; + clock += 4; + break; + + case 0xE5: // SBC zp + operand = 255 - zeroPageRead(eazp()); + result = operand + A + getFC_(); + setV(!(((operand ^ A) & 0x80) != 0) && (((A ^ result) & 0x80) != 0)); + sbcBCDAdjust(); + A = result & 0xff; + NZFlags = A; + clock += 3; + break; + + case 0xE1: // SBC (zp,X) + operand = 255 - memoryRead(eazpxind()); + result = operand + A + getFC_(); + setV(!(((operand ^ A) & 0x80) != 0) && (((A ^ result) & 0x80) != 0)); + sbcBCDAdjust(); + A = result & 0xff; + NZFlags = A; + clock += 6; + break; + + case 0xF1: // SBC (zp),Y + operand = 255 - memoryRead(eazpindy()); + result = operand + A + getFC_(); + setV(!(((operand ^ A) & 0x80) != 0) && (((A ^ result) & 0x80) != 0)); + sbcBCDAdjust(); + A = result & 0xff; + NZFlags = A; + clock += 5; + break; + + case 0xF5: // SBC zp,X + operand = 255 - zeroPageRead(eazpx()); + result = operand + A + getFC_(); + setV(!(((operand ^ A) & 0x80) != 0) && (((A ^ result) & 0x80) != 0)); + sbcBCDAdjust(); + A = result & 0xff; + NZFlags = A; + clock += 4; + break; + + case 0xFD: // SBC abs,X + operand = 255 - memoryRead(eaabsx()); + result = operand + A + getFC_(); + setV(!(((operand ^ A) & 0x80) != 0) && (((A ^ result) & 0x80) != 0)); + sbcBCDAdjust(); + A = result & 0xff; + NZFlags = A; + clock += 4; + break; + + case 0xF9: // SBC abs,Y + operand = 255 - memoryRead(eaabsy()); + result = operand + A + getFC_(); + setV(!(((operand ^ A) & 0x80) != 0) && (((A ^ result) & 0x80) != 0)); + sbcBCDAdjust(); + A = result & 0xff; + NZFlags = A; + clock += 4; + break; + + case 0x38: // SEC + setFC(true); + clock += 2; + break; + + case 0xF8: // SED + setD(true); + clock += 2; + break; + + case 0x78: // SEI + setI(true); + clock += 2; + break; + + case 0x8D: // STA abs + memoryWrite(eaabs(), A); + clock += 4; + break; + + case 0x85: // STA zp + zeroPageWrite(eazp(), A); + clock += 3; + break; + + case 0x81: // STA (zp,X) + memoryWrite(eazpxind(), A); + clock += 6; + break; + + case 0x91: // STA (zp),Y + memoryWrite(eazpindy(), A); + clock += 6; + break; + + case 0x95: // STA zp,X + zeroPageWrite(eazpx(), A); + clock += 4; + break; + + case 0x9D: // STA abs,X + memoryWrite(eaabsx(), A); + clock += 5; + break; + + case 0x99: // STA abs,Y + memoryWrite(eaabsy(), A); + clock += 5; + break; + + case 0x8E: // STX abs + memoryWrite(eaabs(), X); + clock += 4; + break; + + case 0x86: // STX zp + zeroPageWrite(eazp(), X); + clock += 3; + break; + + case 0x96: // STX zp,Y + zeroPageWrite(eazpy(), X); + clock += 4; + break; + + case 0x8C: // STY abs + memoryWrite(eaabs(), Y); + clock += 4; + break; + + case 0x84: // STY zp + zeroPageWrite(eazp(), Y); + clock += 3; + break; + + case 0x94: // STY zp,X + zeroPageWrite(eazpx(), Y); + clock += 4; + break; + + case 0xAA: // TAX + X = A; + NZFlags = X; + clock += 2; + break; + + case 0xA8: // TAY + Y = A; + NZFlags = Y; + clock += 2; + break; + + case 0xBA: // TSX + X = S; + NZFlags = X; + clock += 2; + break; + + case 0x8A: // TXA + A = X; + NZFlags = A; + clock += 2; + break; + + case 0x9A: // TXS + S = X; + clock += 2; + break; + + case 0x98: // TYA + A = Y; + NZFlags = A; + clock += 2; + break; + + /* + * 65C02 instructions + * note: timing is not correct + */ + + case 0x72: // ADC (zp) + operand = memoryRead(eazpind()); + result = operand + A + getFC_(); + setV(!(((operand ^ A) & 0x80) != 0) && (((A ^ result) & 0x80) != 0)); + adcBCDAdjust(); + A = result & 0xff; + NZFlags = A; + clock += 5; + break; + + case 0x32: // AND (zp) + A &= memoryRead(eazpind()); + NZFlags = A; + clock += 5; + break; + + case 0x34: // BIT zp,X + operand = zeroPageRead(eazpx()); + setV((operand & 0x40) != 0); + NZFlags = ((operand & 0x80) << 2) | (A & operand); + clock += 3; + break; + + case 0x89: // BIT #imm + operand = eaimm(); + setV((operand & 0x40) != 0); + NZFlags = ((operand & 0x80) << 2) | (A & operand); + clock += 2; + break; + + case 0x3C: // BIT abs,X + operand = eaabsx(); + setV((operand & 0x40) != 0); + NZFlags = ((operand & 0x80) << 2) | (A & operand); + clock += 4; + break; + + case 0x80: // BRA rr + operand = earel(); + clock += 2; + branch(operand); + break; + + case 0xD2: // CMP (zp) + result = 0x100 + A - memoryRead(eazpind()); + NZFlags = result; + clock += 5; + break; + + case 0x3A: // DEA acc + NZFlags = A + 0xff; + A = NZFlags & 0xff; + clock += 2; + break; + + case 0x52: // EOR (zp) + A ^= memoryRead(eazpind()); + NZFlags = A; + clock += 5; + break; + + case 0x1A: // INA acc + NZFlags = A + 1; + A = NZFlags & 0xff; + clock += 2; + break; + + case 0x7C: // JMP (abs,X) + PC = eaabsxind(); + clock += 6; + break; + + case 0xB2: // LDA (zp) + A = memoryRead(eazpind()); + NZFlags = A; + clock += 5; + break; + + case 0x12: // ORA (zp) + A |= memoryRead(eazpind()); + NZFlags = A; + clock += 5; + break; + + case 0xDA: // PHX + push(X); + clock += 3; + break; + + case 0xFA: // PLX + X = pop(); + NZFlags = X; + clock += 4; + break; + + case 0x5A: // PHY + push(Y); + clock += 3; + break; + + case 0x7A: // PLY + Y = pop(); + NZFlags = Y; + clock += 4; + break; + + case 0xF2: // SBC (zp) + operand = 255 - memoryRead(eazpind()); + result = operand + A + getFC_(); + setV(!(((operand ^ A) & 0x80) != 0) && (((A ^ result) & 0x80) != 0)); + sbcBCDAdjust(); + A = result & 0xff; + NZFlags = A; + clock += 5; + break; + + case 0x92: // STA (zp) + memoryWrite(eazpind(), A); + clock += 6; + break; + + case 0x9C: // STZ abs + memoryWrite(eaabs(), 0); + clock += 4; + break; + + case 0x64: // STZ zp + zeroPageWrite(eazp(), 0); + clock += 3; + break; + + case 0x74: // STZ zp,X + zeroPageWrite(eazpx(), 0); + clock += 3; + break; + + case 0x9E: // STZ abs,X + memoryWrite(eaabsx(), 0); + clock += 4; + break; + + case 0x1C: // TRB abs + operandAddress = eaabs(); + operand = memoryRead(operandAddress); + setV((operand & 0x40) != 0); + NZFlags = ((operand & 0x80) << 2) | (A & operand); + memoryWrite(operandAddress, (operand & ~A) & 0xff); + clock += 5; + break; + + case 0x14: // TRB zp + operandAddress = eazp(); + operand = zeroPageRead(operandAddress); + setV((operand & 0x40) != 0); + NZFlags = ((operand & 0x80) << 2) | (A & operand); + zeroPageWrite(operandAddress, (operand & ~A) & 0xff); + clock += 5; + break; + + case 0x0C: // TSB abs + operandAddress = eaabs(); + operand = memoryRead(operandAddress); + setV((operand & 0x40) != 0); + NZFlags = ((operand & 0x80) << 2) | (A & operand); + memoryWrite(operandAddress, operand | A); + clock += 5; + break; + + case 0x04: // TSB zp + operandAddress = eazp(); + operand = zeroPageRead(operandAddress); + setV((operand & 0x40) != 0); + NZFlags = ((operand & 0x80) << 2) | (A & operand); + zeroPageWrite(operandAddress, operand | A); + clock += 5; + break; + + default: // unknown instructions + clock += 2; + } + } + + public final int executeInstructions(int num) { + // Initialize + int clockStart = clock; + + for (; num >= 16; num -= 16) { + PC &= 0xffff; // Keep PC "sort of" bounded + executeInstruction(); executeInstruction(); + executeInstruction(); executeInstruction(); + executeInstruction(); executeInstruction(); + executeInstruction(); executeInstruction(); + executeInstruction(); executeInstruction(); + executeInstruction(); executeInstruction(); + executeInstruction(); executeInstruction(); + } + PC &= 0xffff; + for (; num > 0; num--) { + executeInstruction(); + } + + return (clock - clockStart) & 0x7fffffff; + } + + public final void checkInterrupts() { + // Reset + if ((exceptionRegister & SIG_6502_RESET) != 0) { + onReset(); + + A = X = Y = 0; + P = 0x20; + setFC(getC()); + setFNZ(getN(), getZ()); + S = 0xff; + PC = memoryRead(0xfffc); + PC |= (memoryRead(0xfffd) << 8); + exceptionRegister &= ~SIG_6502_RESET; + } + + // No NMI nor IRQ... + if ((exceptionRegister & SIG_6502_NMI) != 0) { + onNMI(); + + push(PC >> 8); + push(PC); + setN(getFN()); + setZ(getFZ()); + setC(getFC()); + push(P); + PC = memoryRead(0xfffa); + PC |= memoryRead(0xfffb) << 8; + clock += 7; + exceptionRegister ^= SIG_6502_NMI; + } + + if ((exceptionRegister & SIG_6502_IRQ) != 0) { + onIRQ(); + + if (getI()) { + pendingIRQ++; + } else { + push(PC >> 8); + push(PC); + setN(getFN()); + setZ(getFZ()); + setC(getFC()); + setB(false); + push(P); + setI(true); + PC = memoryRead(0xfffe); + PC |= memoryRead(0xffff) << 8; + clock += 7; + } + exceptionRegister ^= SIG_6502_IRQ; + } + } +} diff --git a/src/main/java/vavi/apps/appleii/EmAppleII.java b/src/main/java/vavi/apps/appleii/EmAppleII.java new file mode 100644 index 0000000..ecb07a5 --- /dev/null +++ b/src/main/java/vavi/apps/appleii/EmAppleII.java @@ -0,0 +1,1208 @@ +/* + * AppleIIGo + * Apple II Emulator for J2ME + * (C) 2006 by Marc S. Ressl(ressl@lonetree.com) + * Released under the GPL + */ + +package vavi.apps.appleii; + + +public class EmAppleII extends Em6502 implements Runnable { + /* + * Apple II memory map + */ + public static final int MEM_PHYS_ZP = 0x00000; + public static final int MEM_PHYS_STACK = 0x00100; + public static final int MEM_PHYS_RAM1 = 0x00200; + public static final int MEM_PHYS_TEXT = 0x00400; + public static final int MEM_PHYS_RAM2 = 0x00800; + public static final int MEM_PHYS_HIRES = 0x02000; + public static final int MEM_PHYS_RAM3 = 0x04000; + public static final int MEM_PHYS_IO = 0x0c000; + public static final int MEM_PHYS_ROM_LOW = 0x0d000; + public static final int MEM_PHYS_ROM_HIGH = 0x0e000; + + public static final int MEM_MAIN_RAM1 = 0x00200; + public static final int MEM_MAIN_TEXT = 0x00400; + public static final int MEM_MAIN_RAM2 = 0x00800; + public static final int MEM_MAIN_HIRES = 0x02000; + public static final int MEM_MAIN_RAM3 = 0x04000; + public static final int MEM_MAIN_LC1 = 0x0c000; + public static final int MEM_MAIN_LC2 = 0x0d000; + public static final int MEM_MAIN_LC_HIGH = 0x0e000; + + public static final int MEM_AUX_ZP = 0x10000; + public static final int MEM_AUX_STACK = 0x10100; + public static final int MEM_AUX_RAM1 = 0x10200; + public static final int MEM_AUX_TEXT = 0x10400; + public static final int MEM_AUX_RAM2 = 0x10800; + public static final int MEM_AUX_HIRES = 0x12000; + public static final int MEM_AUX_RAM3 = 0x14000; + public static final int MEM_AUX_LC1 = 0x1c000; + public static final int MEM_AUX_LC2 = 0x1d000; + public static final int MEM_AUX_LC_HIGH = 0x1e000; + + public static final int MEM_ROM_MAIN_LOW = 0x20000; + public static final int MEM_ROM_MAIN_HIGH = 0x21000; + public static final int MEM_ROM_INTERNAL = 0x23000; + public static final int MEM_ROM_EXTERNAL = 0x24000; + + public static final int MEM_MAIN_ZP = 0x25000; + public static final int MEM_MAIN_STACK = 0x25100; + + public static final int MEM_WASTE = 0x25200; + + public static final int MEM_END = 0x28000; + + // Peripherals + public Paddle paddle; + public Peripheral[] slots; + + // Graphics (dirty buffer every 0x80 bytes) + public int graphicsMode; + public boolean[] graphicsDirty = new boolean[0x10000 >> 7]; + + public static final int GR_TEXT = (1 << 0); + public static final int GR_MIXMODE = (1 << 1); + public static final int GR_PAGE2 = (1 << 2); + public static final int GR_HIRES = (1 << 3); + public static final int GR_80STORE = (1 << 4); + public static final int GR_80CHAR = (1 << 5); + public static final int GR_ALTCHAR = (1 << 6); + public static final int GR_DHIRES = (1 << 7); + + // Sound + public static final int SPEAKER_FLIPS_SIZE = 4096; + public static final int SPEAKER_FLIPS_MASK = 4095; + + public int speakerFlips[] = new int[SPEAKER_FLIPS_SIZE]; + public int speakerFlipsPointer = 0; + + // Default ROM + private static final int[] defaultRom = { + // Reset routine + 0xad, 0x51, 0xc0, + 0xa9, 0xa0, + + 0xa2, 0xff, 0x9d, 0xff, 0x03, 0xca, 0xd0, 0xfa, + 0xa2, 0xff, 0x9d, 0xff, 0x04, 0xca, 0xd0, 0xfa, + 0xa2, 0xff, 0x9d, 0xff, 0x05, 0xca, 0xd0, 0xfa, + 0xa2, 0xff, 0x9d, 0xff, 0x06, 0xca, 0xd0, 0xfa, + + 0xa2, 0x27, 0xbd, 0xb8, 0xfe, 0x9d, 0x80, 0x04, 0xca, 0x10, 0xf7, + 0xa2, 0x27, 0xbd, 0xe0, 0xfe, 0x9d, 0x00, 0x05, 0xca, 0x10, 0xf7, + 0xa2, 0x27, 0xbd, 0x08, 0xff, 0x9d, 0x80, 0x05, 0xca, 0x10, 0xf7, + 0xa2, 0x27, 0xbd, 0x30, 0xff, 0x9d, 0x00, 0x06, 0xca, 0x10, 0xf7, + 0xa2, 0x27, 0xbd, 0x58, 0xff, 0x9d, 0x80, 0x07, 0xca, 0x10, 0xf7, + 0xa2, 0x27, 0xbd, 0x80, 0xff, 0x9d, 0x28, 0x04, 0xca, 0x10, 0xf7, + 0xa2, 0x27, 0xbd, 0xa8, 0xff, 0x9d, 0x00, 0x07, 0xca, 0x10, 0xf7, + 0xa2, 0x27, 0xbd, 0xd0, 0xff, 0x9d, 0x00, 0x07, 0xca, 0x10, 0xf7, + + 0x4c, 0xad, 0xfe, + 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, + + // Text message + 0xa0, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xa0, + + 0xa0, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0x10, 0x10, 0x0c, 0x05, 0x09, 0x09, + 0x07, 0x0f, 0x20, 0x12, 0x05, 0x11, 0x15, 0x09, 0x12, 0x05, 0x13, 0x20, 0x01, 0x0e, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xa0, // APPLEIIGO REQUIRES AN + + 0xa0, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0x10, 0x10, 0x0c, 0x05, 0x20, 0x09, 0x09, 0x20, + 0x12, 0x0f, 0x0d, 0x20, 0x09, 0x0d, 0x01, 0x07, 0x05, 0x20, 0x14, 0x0f, 0x20, 0x12, 0x15, 0x0e, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xa0, // APPLE II ROM IMAGE TO RUN + + 0xa0, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xa0, + + 0xa0, 0xc6, 0xcf, 0xd2, 0xa0, 0xcd, 0xcf, 0xd2, 0xc5, 0xa0, 0xc9, 0xce, 0xc6, 0xcf, 0xd2, 0xcd, + 0xc1, 0xd4, 0xc9, 0xcf, 0xce, 0xa0, 0xd0, 0xcc, 0xc5, 0xc1, 0xd3, 0xc5, 0xa0, 0xc3, 0xcc, 0xc9, + 0xc3, 0xcb, 0xa0, 0xcf, 0xce, 0xa0, 0xa0, 0xa0, // FOR MORE INFORMATION PLEASE CLICK ON + + 0xa0, 0xd4, 0xc8, 0xc5, 0xa0, 0xc1, 0xd0, 0xd0, 0xcc, 0xc5, 0xc9, 0xc9, 0xc7, 0xcf, 0xa0, 0xcc, + 0xcf, 0xc7, 0xcf, 0xa0, 0xc2, 0xc5, 0xcc, 0xcf, 0xd7, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, // THE APPLEIIGO LOGO BELOW + + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + + // Interrupt vectors + 0x00, 0x00, 0x30, 0xfe, 0x30, 0xfe, 0x30, 0xfe + }; + + // Emulator + private boolean isRestart; + + private int cpuSpeed; + private int clocksPerInterval; + + private int refreshRate; + private long refreshInterval; + private long refreshDelayCumulative; + private long refreshDelayPerSecond; + private long refreshCycle; + + // Keyboard + private int keyboardLatch; + + // Memory offsets + private int[] memoryReadOffset = new int[0x101]; + private int[] memoryWriteOffset = new int[0x101]; + + // Language card state + private boolean isLcReadEnable; + private boolean isLcWriteEnable; + private boolean isLcBank2; + + // Apple IIe state + private boolean isRomInternal; + private boolean isRomC3External; + private boolean isAuxRead; + private boolean isAuxWrite; + private boolean isAuxZeroPage; + private boolean isVideoVBL; + + // Thread stuff + private boolean isPaused = true; + private Thread thread; + + // Step mode + private boolean isStepMode = false; + private boolean isNextStep = false; + private int stepCount; + +AppleIIGo.View view; + + /** + * Apple II class constructor + */ + public EmAppleII(AppleIIGo.View view) { +this.view = view; + + // Allocate compute memory + mem = new byte[MEM_END]; + + // Initialize CPU + initMemoryMap(); + setRandomSeed(); + setCpuSpeed(1000); + reset(); + + // Setup default ROM + loadDefaultRom(); + + // Setup paddles + paddle = new Paddle(this); + + // Setup expansion slots + slots = new Peripheral[8]; + for (int slot = 1; slot < 8; slot++) { + setPeripheral(new Peripheral(), slot); + } + } + + /** + * Set random seed (so programs start randomly) + */ + public void setRandomSeed() { + mem[0xcd] = (byte) System.currentTimeMillis(); + } + + /** + * Load default ROM + */ + public void loadDefaultRom() { + for (int offset = 0; offset < 0x1d0; offset++) { + mem[(MEM_ROM_MAIN_LOW + 0x3000 - 0x1d0) + offset] = (byte) defaultRom[offset]; + } + } + + /** + * Loads ROM + */ + private boolean isValidRom(byte[] rom, int offset) { + // Integer BASIC? + if ((rom[offset + 0x1000] & 0xff) == 0x20) { +System.err.println("ROM: Integer BASIC"); + return true; + } + + // Applesoft BASIC? + if ((rom[offset + 0x1000] & 0xff) == 0x4c) { +System.err.println("ROM: Applesoft BASIC"); + return true; + } + + return false; + } + + /** + * @throws IllegalStateException + */ + public void loadRom(AppleIIGo.Dao dao, String resource) { + byte[] rom = new byte[0x8000]; + int offset = 0; + + dao.openInputStream(resource); + dao.read(rom, 0, 0x08000); + dao.closeInputStream(); + + if (isValidRom(rom, 0x0)) { + offset = 0x0; + } else if (isValidRom(rom, 0x1000)) { + offset = 0x1000; + } else if (isValidRom(rom, 0x2000)) { + offset = 0x2000; + } else { + throw new IllegalArgumentException(resource); + } + + // Copy main ROM + System.arraycopy(rom, offset, mem, MEM_ROM_MAIN_LOW, 0x03000); + + // Copy internal ROM + System.arraycopy(rom, offset + 0x3000, mem, MEM_ROM_INTERNAL + 0x00000, 0x01000); + System.arraycopy(rom, offset + 0x3800, mem, MEM_ROM_EXTERNAL + 0x00800, 0x00800); + } + + /** + * Set peripheral + */ + public void setPeripheral(Peripheral peripheral, int slot) { + slots[slot] = peripheral; + + int offset = MEM_ROM_EXTERNAL + (slot << 8); + for (int i = 0; i < 0x100; i++) { + mem[offset + i] = (byte) peripheral.memoryRead(i); + } + } + + /** + * Set pause state + */ + public void setPaused(boolean value) { + if (isPaused == value) { + return; + } + + isPaused = value; + if (isPaused) { + try { + thread.join(1000); + } catch (InterruptedException e) { + } + } else { + thread = new Thread(this); + thread.start(); + } + } + + /** + * Get pause state + */ + public boolean getPaused() { + return isPaused; + } + + /** + * Keyboard push key function + */ + public void setKeyLatch(int key) { + key &= 0x7f; + keyboardLatch = (key | 0x80); +System.err.println("APPLE: " + keyboardLatch + ", " + ((char) key)); + } + + /** + * Restart + */ + public void restart() { + isRestart = true; + assertReset(); + } + + /** + * Reset + */ + public void reset() { + isRestart = false; + assertReset(); + } + + /** + * Set CPU speed + */ + public void setCpuSpeed(int value) { + if (value < 0) { + return; + } + + cpuSpeed = value; + + refreshRate = 20; + refreshInterval = (int) (1000.0 / refreshRate); + clocksPerInterval = (int) (cpuSpeed * refreshInterval); + } + + /** + * Get debug mode + */ + public int getCpuSpeed() { + return cpuSpeed; + } + + /** + * Get refresh rate + */ + public int getRefreshRate() { + return refreshRate; + } + + /** + * Set debug mode + */ + public void setStepMode(boolean value) { + isNextStep = false; + isStepMode = value; + } + + /** + * Get debug mode + */ + public boolean getStepMode() { + return isStepMode; + } + + /** + * Step instruction in debug mode + */ + public void stepInstructions(int value) { + if (value <= 0) { + return; + } + + stepCount = value; + isNextStep = true; + } + + /** + * Zero pad + */ + private String zeroPad(String value, int length) { + length -= value.length(); + + while (length > 0) { + value = "0" + value; + length--; + } + + return value; + } + + /** + * Print a hex value + */ + private String formatHex(int value, int length) { + return zeroPad(Integer.toString(value, 16), length); + } + + /** + * Print a decimal value + */ + private String formatDec(int value, int commaPos) { + String valueString = zeroPad(Integer.toString(value), commaPos + 1); + int length = valueString.length(); + + return valueString.substring(0, length - commaPos) + + "." + valueString.substring(length - commaPos, length); + } + + /** + * Step instruction in debug mode + */ + public String getStatInfo() { + StringBuffer statInfo = new StringBuffer(); + long cpuSpeedCurrent; + + // Calculate effective CPU speed + if (isPaused || isStepMode) { + cpuSpeedCurrent = 0; + } else if (refreshDelayPerSecond > 1000) { + cpuSpeedCurrent = cpuSpeed * 1000 / refreshDelayPerSecond; + } else { + cpuSpeedCurrent = cpuSpeed; + } + + // Return A, X, Y, S, P, PC + statInfo.append(" A=").append(formatHex(A, 2)); + statInfo.append(" X=").append(formatHex(X, 2)); + statInfo.append(" Y=").append(formatHex(Y, 2)); + statInfo.append(" P=").append(formatHex(P, 2)); + statInfo.append(" S=").append(formatHex(S, 2)); + statInfo.append("\n"); + statInfo.append(" PC=").append(formatHex(PC, 4)).append("\n"); + statInfo.append(" [PC]="); + statInfo.append(" ").append(formatHex(memoryRead(PC + 0), 2)); + statInfo.append(" ").append(formatHex(memoryRead(PC + 1), 2)); + statInfo.append(" ").append(formatHex(memoryRead(PC + 2), 2)); + statInfo.append(" ").append(formatHex(memoryRead(PC + 3), 2)); + statInfo.append("\n"); + statInfo.append(" MHZ=").append(formatDec((int) cpuSpeedCurrent, 3)).append(" [").append(refreshDelayPerSecond).append(" ms/s]\n"); + + return statInfo.toString(); + } + + /** + * Noise function + * + * We assume a "sort-of" floating bus + * (spanning memory locations 0000-3FFF) + * + * Correct way: We should look up the current video mode, + * and sample according to what is being shown. + */ + public int noise() { + return mem[clock & 0x3fff]; + } + + /** + * Read memory function + * + * @param address Address + */ + protected int memoryRead(int address) { + if ((address & 0xff00) == 0xc000) { + return ioRead(address); + } + + return mem[address + memoryReadOffset[address >> 8]] & 0xff; + } + + /** + * Write memory function + * + * @param adderss Address + * @param value value + */ + protected void memoryWrite(int address, int value) { + if ((address & 0xff00) == 0xc000) { + ioWrite(address, value); + } else { + mem[address + memoryWriteOffset[address >> 8]] = (byte) value; + graphicsDirty[address >> 7] = true; + } + } + + /** + * Update memory maps + */ + private void updateMainMemoryMap() { + int ramReadOffset, textReadOffset, hiresReadOffset; + int ramWriteOffset, textWriteOffset, hiresWriteOffset; + boolean isPage2 = ((graphicsMode & GR_PAGE2) != 0); + boolean is80STORE = ((graphicsMode & GR_80STORE) != 0); + boolean isHires = ((graphicsMode & GR_HIRES) != 0); + + textReadOffset = hiresReadOffset = ramReadOffset = isAuxRead ? + (MEM_AUX_RAM1 - MEM_PHYS_RAM1) : (MEM_MAIN_RAM1 - MEM_PHYS_RAM1); + textWriteOffset = hiresWriteOffset = ramWriteOffset = isAuxWrite ? + (MEM_AUX_RAM1 - MEM_PHYS_RAM1) : (MEM_MAIN_RAM1 - MEM_PHYS_RAM1); + + if (is80STORE) { + textWriteOffset = textReadOffset = isPage2 ? (MEM_AUX_TEXT - MEM_PHYS_TEXT) : + (MEM_MAIN_TEXT - MEM_PHYS_TEXT); + + if (isHires) { + hiresWriteOffset = hiresReadOffset = textReadOffset; + } + } + + memoryReadOffset[0x02] = memoryReadOffset[0x03] = ramReadOffset; + memoryWriteOffset[0x02] = memoryWriteOffset[0x03] = ramWriteOffset; + memoryReadOffset[0x04] = memoryReadOffset[0x05] = memoryReadOffset[0x06] = memoryReadOffset[0x07] = textReadOffset; + memoryWriteOffset[0x04] = memoryWriteOffset[0x05] = memoryWriteOffset[0x06] = memoryWriteOffset[0x07] = textWriteOffset; + for (int offset = 0x08; offset < 0x20; offset++) { + memoryReadOffset[offset] = ramReadOffset; + memoryWriteOffset[offset] = ramWriteOffset; + } + for (int offset = 0x20; offset < 0x40; offset++) { + memoryReadOffset[offset] = hiresReadOffset; + memoryWriteOffset[offset] = hiresWriteOffset; + } + for (int offset = 0x40; offset < 0xc0; offset++) { + memoryReadOffset[offset] = ramReadOffset; + memoryWriteOffset[offset] = ramWriteOffset; + } + } + + private void updateIOMemoryMap() { + int romOffset; + + if (isRomInternal) { + romOffset = (MEM_ROM_INTERNAL - MEM_PHYS_IO); + } else { + romOffset = (MEM_ROM_EXTERNAL - MEM_PHYS_IO); + } + + for (int offset = 0xc1; offset < 0xd0; offset++) { + memoryReadOffset[offset] = romOffset; + } + + if (isRomC3External) { + memoryReadOffset[0xc3] = (MEM_ROM_EXTERNAL - MEM_PHYS_IO); + } else { + memoryReadOffset[0xc3] = (MEM_ROM_INTERNAL - MEM_PHYS_IO); + } + } + + private void initIOMemoryMap() { + for (int offset = 0xc1; offset < 0xd0; offset++) { + memoryWriteOffset[offset] = (MEM_WASTE - MEM_PHYS_IO); + } + } + + private void updateLCMemoryMap() { + int lcReadOffset, lcReadOffsetHigh; + int lcWriteOffset, lcWriteOffsetHigh; + + if (!isLcReadEnable) { + lcReadOffset = (MEM_ROM_MAIN_LOW - MEM_PHYS_ROM_LOW); + lcReadOffsetHigh = (MEM_ROM_MAIN_LOW - MEM_PHYS_ROM_LOW); + } else if (isAuxZeroPage) { + lcReadOffset = isLcBank2 ? (MEM_AUX_LC2 - MEM_PHYS_ROM_LOW) : (MEM_AUX_LC1 - MEM_PHYS_ROM_LOW); + lcReadOffsetHigh = (MEM_AUX_LC_HIGH - MEM_PHYS_ROM_HIGH); + } else { + lcReadOffset = isLcBank2 ? (MEM_MAIN_LC2 - MEM_PHYS_ROM_LOW) : (MEM_MAIN_LC1 - MEM_PHYS_ROM_LOW); + lcReadOffsetHigh = (MEM_MAIN_LC_HIGH - MEM_PHYS_ROM_HIGH); + } + + if (!isLcWriteEnable) { + lcWriteOffset = (MEM_WASTE - MEM_PHYS_ROM_LOW); + lcWriteOffsetHigh = (MEM_WASTE - MEM_PHYS_ROM_HIGH); + } else if (isAuxZeroPage) { + lcWriteOffset = isLcBank2 ? (MEM_AUX_LC2 - MEM_PHYS_ROM_LOW) : (MEM_AUX_LC1 - MEM_PHYS_ROM_LOW); + lcWriteOffsetHigh = (MEM_AUX_LC_HIGH - MEM_PHYS_ROM_HIGH); + } else { + lcWriteOffset = isLcBank2 ? (MEM_MAIN_LC2 - MEM_PHYS_ROM_LOW) : (MEM_MAIN_LC1 - MEM_PHYS_ROM_LOW); + lcWriteOffsetHigh = (MEM_MAIN_LC_HIGH - MEM_PHYS_ROM_HIGH); + } + + for (int offset = 0xd0; offset < 0xe0; offset++) { + memoryReadOffset[offset] = lcReadOffset; + memoryWriteOffset[offset] = lcWriteOffset; + } + for (int offset = 0xe0; offset < 0x100; offset++) { + memoryReadOffset[offset] = lcReadOffsetHigh; + memoryWriteOffset[offset] = lcWriteOffsetHigh; + } + } + + void initMemoryMap() { + initIOMemoryMap(); + + updateMainMemoryMap(); + updateIOMemoryMap(); + updateLCMemoryMap(); + } + + /** + * Apple I/O reads + * + * @param address Address + */ + private int ioRead(int address) { + address &= 0xff; + + if (address >= 0x90) { + return slots[(address & 0x70) >> 4].ioRead(address); + } + + switch (address) { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + // Keyboard data +//System.err.println("io: " + address + ": " + keyboardLatch); + return keyboardLatch; + + case 0x10: + // Keyboard strobe + keyboardLatch &= 0x7f; + return keyboardLatch; + case 0x11: + // Reading from LC Bank 2? + return (keyboardLatch & 0x7f) | (isLcBank2 ? 0x80 : 0x00); + case 0x12: + // Reading from LC? + return (keyboardLatch & 0x7f) | (isLcReadEnable ? 0x80 : 0x00); + case 0x13: + // Reading aux memory? + return (keyboardLatch & 0x7f) | (isAuxRead ? 0x80 : 0x00); + case 0x14: + // Writing aux memory? + return (keyboardLatch & 0x7f) | (isAuxWrite ? 0x80 : 0x00); + case 0x15: + // Using internal slot ROM? + return (keyboardLatch & 0x7f) | (isRomInternal ? 0x80 : 0x00); + case 0x16: + // Using slot zero page+stack+LC? + return (keyboardLatch & 0x7f) | (isAuxZeroPage ? 0x80 : 0x00); + case 0x17: + // Using external slot 3 ROM? + return (keyboardLatch & 0x7f) | (isRomC3External ? 0x80 : 0x00); + case 0x18: + // 80STORE? + return (keyboardLatch & 0x7f) | (((graphicsMode & GR_80STORE) != 0) ? 0x80 : 0x00); + case 0x19: + // VBL Signal low? + isVideoVBL = !isVideoVBL; + return (keyboardLatch & 0x7f) | (isVideoVBL ? 0x80 : 0x00); + case 0x1a: + // Using text mode? + return (keyboardLatch & 0x7f) | (((graphicsMode & GR_TEXT) != 0) ? 0x80 : 0x00); + case 0x1b: + // Using mixed mode? + return (keyboardLatch & 0x7f) | (((graphicsMode & GR_MIXMODE) != 0) ? 0x80 : 0x00); + case 0x1c: + // Using page 2? + return (keyboardLatch & 0x7f) | (((graphicsMode & GR_PAGE2) != 0) ? 0x80 : 0x00); + case 0x1d: + // Using hires? + return (keyboardLatch & 0x7f) | (((graphicsMode & GR_HIRES) != 0) ? 0x80 : 0x00); + case 0x1e: + // Using alt charset? + return (keyboardLatch & 0x7f) | (((graphicsMode & GR_ALTCHAR) != 0) ? 0x80 : 0x00); + case 0x1f: + // Using 80-column display mode? + return (keyboardLatch & 0x7f) | (((graphicsMode & GR_80CHAR) != 0) ? 0x80 : 0x00); + + case 0x20: case 0x21: case 0x22: case 0x23: + case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: + case 0x2c: case 0x2d: case 0x2e: case 0x2f: + // Cassette output + break; + + case 0x30: case 0x31: case 0x32: case 0x33: + case 0x34: case 0x35: case 0x36: case 0x37: + case 0x38: case 0x39: case 0x3a: case 0x3b: + case 0x3c: case 0x3d: case 0x3e: case 0x3f: + // Speaker + speakerFlips[speakerFlipsPointer] = clock; + speakerFlipsPointer = (speakerFlipsPointer + 1) & SPEAKER_FLIPS_MASK; + break; + + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + // Game strobe + break; + + case 0x50: + graphicsMode &= ~GR_TEXT; + break; + case 0x51: + graphicsMode |= GR_TEXT; + break; + case 0x52: + graphicsMode &= ~GR_MIXMODE; + break; + case 0x53: + graphicsMode |= GR_MIXMODE; + break; + case 0x54: + graphicsMode &= ~GR_PAGE2; + updateMainMemoryMap(); + break; + case 0x55: + graphicsMode |= GR_PAGE2; + updateMainMemoryMap(); + break; + case 0x56: + graphicsMode &= ~GR_HIRES; + updateMainMemoryMap(); + break; + case 0x57: + graphicsMode |= GR_HIRES; + updateMainMemoryMap(); + break; + case 0x58: case 0x59: case 0x5a: case 0x5b: + case 0x5c: case 0x5d: + // Annunciators + break; + case 0x5e: + graphicsMode |= GR_DHIRES; + break; + case 0x5f: + graphicsMode &= ~GR_DHIRES; + break; + + case 0x60: + case 0x68: + // (Also cassette input) + return paddle.getButtonRegister(3); + case 0x61: + case 0x69: + return paddle.getButtonRegister(0); + case 0x62: + case 0x6a: + return paddle.getButtonRegister(1); + case 0x63: + case 0x6b: + return paddle.getButtonRegister(2); + case 0x64: + case 0x6c: + return paddle.getPaddleRegister(0); + case 0x65: + case 0x6d: + return paddle.getPaddleRegister(1); + case 0x66: + case 0x6e: + return paddle.getPaddleRegister(2); + case 0x67: + case 0x6f: + return paddle.getPaddleRegister(3); + + case 0x70: case 0x71: case 0x72: case 0x73: + case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: + case 0x7c: case 0x7d: case 0x7e: case 0x7f: + paddle.triggerRegister(); + break; + + case 0x80: + case 0x84: + isLcBank2 = true; + isLcReadEnable = true; + isLcWriteEnable = false; + updateLCMemoryMap(); + break; + case 0x81: + case 0x85: + isLcBank2 = true; + isLcReadEnable = false; + isLcWriteEnable = true; + updateLCMemoryMap(); + break; + case 0x82: + case 0x86: + isLcBank2 = true; + isLcReadEnable = false; + isLcWriteEnable = false; + updateLCMemoryMap(); + break; + case 0x83: + case 0x87: + isLcBank2 = true; + isLcReadEnable = true; + isLcWriteEnable = true; + updateLCMemoryMap(); + break; + case 0x88: + case 0x8c: + isLcBank2 = false; + isLcReadEnable = true; + isLcWriteEnable = false; + updateLCMemoryMap(); + break; + case 0x89: + case 0x8d: + isLcBank2 = false; + isLcReadEnable = false; + isLcWriteEnable = true; + updateLCMemoryMap(); + break; + case 0x8a: + case 0x8e: + isLcBank2 = false; + isLcReadEnable = false; + isLcWriteEnable = false; + updateLCMemoryMap(); + break; + case 0x8b: + case 0x8f: + isLcBank2 = false; + isLcReadEnable = true; + isLcWriteEnable = true; + updateLCMemoryMap(); + break; + case 0x90: case 0x91: case 0x92: case 0x93: + case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: + case 0x9c: case 0x9d: case 0x9e: case 0x9f: + return slots[1].ioRead(address); + + case 0xa0: case 0xa1: case 0xa2: case 0xa3: + case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: + case 0xac: case 0xad: case 0xae: case 0xaf: + return slots[2].ioRead(address); + + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: + case 0xbc: case 0xbd: case 0xbe: case 0xbf: + return slots[3].ioRead(address); + + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: + case 0xcc: case 0xcd: case 0xce: case 0xcf: + return slots[4].ioRead(address); + + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: + case 0xdc: case 0xdd: case 0xde: case 0xdf: + return slots[5].ioRead(address); + + case 0xe0: case 0xe1: case 0xe2: case 0xe3: + case 0xe4: case 0xe5: case 0xe6: case 0xe7: + case 0xe8: case 0xe9: case 0xea: case 0xeb: + case 0xec: case 0xed: case 0xee: case 0xef: + return slots[6].ioRead(address); + + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: case 0xff: + return slots[7].ioRead(address); + } + + return noise(); + } + + /** + * Apple I/O writes + * + * @param address Address + * @param value Value + */ + private void ioWrite(int address, int value) { + address &= 0xff; + + if (address >= 0x90) { + slots[(address & 0x70) >> 4].ioWrite(address, value); + return; + } + + switch (address) { + case 0x00: + // 80STORE off + graphicsMode &= ~GR_80STORE; + updateMainMemoryMap(); + return; + case 0x01: + // 80STORE on + graphicsMode |= GR_80STORE; + updateMainMemoryMap(); + return; + case 0x02: + // Read aux mem off + isAuxRead = false; + updateMainMemoryMap(); + return; + case 0x03: + // Read aux mem on + isAuxRead = true; + updateMainMemoryMap(); + return; + case 0x04: + // Write aux mem off + isAuxWrite = false; + updateMainMemoryMap(); + return; + case 0x05: + // Write aux mem on + isAuxWrite = true; + updateMainMemoryMap(); + return; + case 0x06: + // Do not use internal ROM + isRomInternal = false; + updateIOMemoryMap(); + return; + case 0x07: + // Use internal ROM + isRomInternal = true; + updateIOMemoryMap(); + return; + case 0x08: + if (isAuxZeroPage) { + // Physically get main zero page + System.arraycopy(mem, MEM_PHYS_ZP, mem, MEM_AUX_ZP, 0x200); + System.arraycopy(mem, MEM_MAIN_ZP, mem, MEM_PHYS_ZP, 0x200); + } + // Aux zero page off + isAuxZeroPage = false; + updateLCMemoryMap(); + return; + case 0x09: + if (!isAuxZeroPage) { + // Physically get aux zero page + System.arraycopy(mem, MEM_PHYS_ZP, mem, MEM_MAIN_ZP, 0x200); + System.arraycopy(mem, MEM_AUX_ZP, mem, MEM_PHYS_ZP, 0x200); + } + // Aux zero page on + isAuxZeroPage = true; + updateLCMemoryMap(); + return; + case 0x0a: + // Do not use external slot 3 ROM + isRomC3External = false; + updateIOMemoryMap(); + return; + case 0x0b: + // Use external slot 3 ROM + isRomC3External = true; + updateIOMemoryMap(); + return; + case 0x0c: + // 80c off + graphicsMode &= ~GR_80CHAR; + return; + case 0x0d: + // 80c on + graphicsMode |= GR_80CHAR; + return; + case 0x0e: + // Alt charset off + graphicsMode &= ~GR_ALTCHAR; + return; + case 0x0f: + // Alt charset on + graphicsMode |= GR_ALTCHAR; + return; + + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: + case 0x1c: case 0x1d: case 0x1e: case 0x1f: + // Keyboard strobe + keyboardLatch &= 0x7f; +//System.err.println("io: " + address + ": " + keyboardLatch); + return; + + case 0x20: case 0x21: case 0x22: case 0x23: + case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: + case 0x2c: case 0x2d: case 0x2e: case 0x2f: + // Cassette output + return; + + case 0x30: case 0x31: case 0x32: case 0x33: + case 0x34: case 0x35: case 0x36: case 0x37: + case 0x38: case 0x39: case 0x3a: case 0x3b: + case 0x3c: case 0x3d: case 0x3e: case 0x3f: + // Speaker + speakerFlips[speakerFlipsPointer] = clock; + speakerFlipsPointer = (speakerFlipsPointer + 1) & SPEAKER_FLIPS_MASK; + return; + + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + // Game strobe + return; + + case 0x50: + graphicsMode &= ~GR_TEXT; + return; + case 0x51: + graphicsMode |= GR_TEXT; + return; + case 0x52: + graphicsMode &= ~GR_MIXMODE; + return; + case 0x53: + graphicsMode |= GR_MIXMODE; + return; + case 0x54: + graphicsMode &= ~GR_PAGE2; + updateMainMemoryMap(); + return; + case 0x55: + graphicsMode |= GR_PAGE2; + updateMainMemoryMap(); + return; + case 0x56: + graphicsMode &= ~GR_HIRES; + updateMainMemoryMap(); + return; + case 0x57: + graphicsMode |= GR_HIRES; + updateMainMemoryMap(); + return; + case 0x58: case 0x59: case 0x5a: case 0x5b: + case 0x5c: case 0x5d: + // Annunciators + return; + case 0x5e: + graphicsMode |= GR_DHIRES; + break; + case 0x5f: + graphicsMode &= ~GR_DHIRES; + break; + + case 0x60: case 0x61: case 0x62: case 0x63: + case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + // Cassette input/paddle data + return; + + case 0x70: case 0x71: case 0x72: case 0x73: + case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: + case 0x7c: case 0x7d: case 0x7e: case 0x7f: + paddle.triggerRegister(); + return; + + case 0x80: + case 0x84: + isLcBank2 = true; + isLcReadEnable = true; + isLcWriteEnable = false; + updateLCMemoryMap(); + break; + case 0x81: + case 0x85: + isLcBank2 = true; + isLcReadEnable = false; + isLcWriteEnable = true; + updateLCMemoryMap(); + break; + case 0x82: + case 0x86: + isLcBank2 = true; + isLcReadEnable = false; + isLcWriteEnable = false; + updateLCMemoryMap(); + break; + case 0x83: + case 0x87: + isLcBank2 = true; + isLcReadEnable = true; + isLcWriteEnable = true; + updateLCMemoryMap(); + break; + case 0x88: + case 0x8c: + isLcBank2 = false; + isLcReadEnable = true; + isLcWriteEnable = false; + updateLCMemoryMap(); + break; + case 0x89: + case 0x8d: + isLcBank2 = false; + isLcReadEnable = false; + isLcWriteEnable = true; + updateLCMemoryMap(); + break; + case 0x8a: + case 0x8e: + isLcBank2 = false; + isLcReadEnable = false; + isLcWriteEnable = false; + updateLCMemoryMap(); + break; + case 0x8b: + case 0x8f: + isLcBank2 = false; + isLcReadEnable = true; + isLcWriteEnable = true; + updateLCMemoryMap(); + break; + } + } + + /** + * Emulator thread + */ + public void run() { + try { + while (!isPaused) { + long refreshStart = System.currentTimeMillis(); + long refreshDelay; + + checkInterrupts(); + + if (isStepMode) { + if (isNextStep) { + isNextStep = false; + executeInstructions(stepCount); + } + } else { + int clocksNeeded = clocksPerInterval; + while (clocksNeeded > 0) { + clocksNeeded -= executeInstructions(1 + (clocksNeeded >> 3)); + } + } + + refreshDelay = System.currentTimeMillis() - refreshStart; + + refreshDelayCumulative += refreshDelay; + refreshCycle++; + if (refreshCycle >= refreshRate) { + refreshDelayPerSecond = refreshDelayCumulative; + refreshDelayCumulative = refreshCycle = 0; + } + + if (refreshDelay < refreshInterval) { + Thread.sleep(refreshInterval - refreshDelay); + } + } + } catch (Throwable e) { +view.debug(e); +view.repaint(); + } + } + + /** + * Reset assertion code + */ + protected void onReset() { + // Reset IOU + MMU + ioWrite(0x00, 0); + ioWrite(0x02, 0); + ioWrite(0x04, 0); + ioWrite(0x06, 0); + ioWrite(0x08, 0); + ioWrite(0x0a, 0); + ioWrite(0x0c, 0); + ioWrite(0x0e, 0); + ioWrite(0x50, 0); + ioWrite(0x52, 0); + ioWrite(0x54, 0); + ioWrite(0x56, 0); + ioWrite(0x5F, 0); + ioWrite(0x82, 0); + + if (isRestart) { + // Clear RAM + for (int i = 0; i < MEM_ROM_MAIN_LOW; i++) { + mem[i] = 0; + } + + setRandomSeed(); + } + + // Reset devices + for (int slot = 1; slot < 8; slot++) { + slots[slot].reset(); + } + } +} diff --git a/src/main/java/vavi/apps/appleii/Paddle.java b/src/main/java/vavi/apps/appleii/Paddle.java new file mode 100644 index 0000000..705452f --- /dev/null +++ b/src/main/java/vavi/apps/appleii/Paddle.java @@ -0,0 +1,102 @@ +/* + * AppleIIGo + * Apple II Emulator for J2ME + * (C) 2006 by Marc S. Ressl(ressl@lonetree.com) + * Released under the GPL + */ + +package vavi.apps.appleii; + + +public class Paddle { + // Public variables + public static final int PADDLE_LOW = 0; + public static final int PADDLE_CENTER = 127; + public static final int PADDLE_HIGH = 255; + + public static final int PADDLEMODE_DIRECT = 0; + public static final int PADDLEMODE_FILTERED = 1; + + // Instances of other classes + private EmAppleII apple; + + // Button variables + private int[] buttonRegister = new int[4]; + + // Paddle variables +// private int paddleMode; + + private int[] paddleClockEvent = new int[4]; + private int[] paddleClockInc = new int[4]; + + /** + * Paddle class constructor + * + * @param apple The EmAppleII instance + */ + public Paddle(EmAppleII apple) { + this.apple = apple; + + setPaddlePos(0, PADDLE_CENTER); + setPaddlePos(1, PADDLE_CENTER); + setPaddlePos(2, PADDLE_CENTER); + setPaddlePos(3, PADDLE_CENTER); + } + + /** + * Set button state + * + * @param button Paddle button + * @param state State + */ + public void setButton(int button, boolean pressed) { + buttonRegister[button] = (pressed ? 0x80 : 0x00); + } + + /** + * Button register + * + * @param button Paddle button + */ + public int getButtonRegister(int button) { + return buttonRegister[button]; + } + + /** + * Set paddle position + * + * @param address Address + * @param value Value + */ + public void setPaddlePos(int paddle, int value) { + /* + * Magic formula, see ROM $FB1E-$FB2E, + * We calculate the numbers of cycles after which + * the RC circuit of a triggered paddle will discharge. + */ + paddleClockInc[paddle] = value * 11 + 8; + } + + /** + * Trigger paddle register + * + * @param address Address + * @param value Value + */ + public void triggerRegister() { + paddleClockEvent[0] = apple.clock + paddleClockInc[0]; + paddleClockEvent[1] = apple.clock + paddleClockInc[1]; + paddleClockEvent[2] = apple.clock + paddleClockInc[2]; + paddleClockEvent[3] = apple.clock + paddleClockInc[3]; + } + + /** + * Get paddle register + * + * @param address Address + * @param value Value + */ + public int getPaddleRegister(int paddle) { + return ((((paddleClockEvent[paddle] - apple.clock) & 0x7fffffff) < 0x40000000) ? 0x80 : 0x00); + } +} diff --git a/src/main/java/vavi/apps/appleii/Peripheral.java b/src/main/java/vavi/apps/appleii/Peripheral.java new file mode 100644 index 0000000..67612f4 --- /dev/null +++ b/src/main/java/vavi/apps/appleii/Peripheral.java @@ -0,0 +1,36 @@ +/* + * AppleIIGo + * Slot interface + * (C) 2006 by Marc S. Ressl(ressl@lonetree.com) + * Released under the GPL + * Based on work by Steven E. Hugg + */ + +package vavi.apps.appleii; + +import java.util.Random; + + +public class Peripheral { + protected Random rand = new Random(); + + public Peripheral() { + } + + public int ioRead(int address) { + return rand.nextInt(256); + } + + public void ioWrite(int address, int value) { + } + + public int memoryRead(int address) { + return 0; + } + + public void memoryWrite(int address, int value) { + } + + public void reset() { + } +} diff --git a/src/main/resources/Character Set.png b/src/main/resources/Character Set.png new file mode 100644 index 0000000..7456b9a Binary files /dev/null and b/src/main/resources/Character Set.png differ diff --git a/src/main/resources/Glare.png b/src/main/resources/Glare.png new file mode 100644 index 0000000..3446ef8 Binary files /dev/null and b/src/main/resources/Glare.png differ diff --git a/src/main/resources/Paused.png b/src/main/resources/Paused.png new file mode 100644 index 0000000..397aad4 Binary files /dev/null and b/src/main/resources/Paused.png differ diff --git a/src/main/resources/disk.png b/src/main/resources/disk.png new file mode 100644 index 0000000..ddc5453 Binary files /dev/null and b/src/main/resources/disk.png differ diff --git a/src/main/resources/keyboard.png b/src/main/resources/keyboard.png new file mode 100644 index 0000000..f35211c Binary files /dev/null and b/src/main/resources/keyboard.png differ diff --git a/src/test/java/vavi/apps/appleii/VirtualKeyboard.java b/src/test/java/vavi/apps/appleii/VirtualKeyboard.java new file mode 100644 index 0000000..530ed59 --- /dev/null +++ b/src/test/java/vavi/apps/appleii/VirtualKeyboard.java @@ -0,0 +1,783 @@ +/* + * $LastChangedDate: 2005-11-21 02:11:20 +0900 (ì›? 21 11 2005) $ + * + * Copyright 1990-2006 Sun Microsystems, Inc. All rights reserved. + * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ + +package vavi.apps.appleii; + +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Toolkit; +import java.awt.event.KeyEvent; + + +/** + * This is a popup layer that handles a sub-popup within the text tfContext + * + * @author Amir Uval + */ + +class VirtualKeyboard { + + /** indicates whether the virtual keyboard is enabled */ + public static boolean USE_VIRTUAL_KEYBOARD = true; + + /** indicates whether the virtual keypad is enabled */ + public static final boolean USE_VIRTUAL_KEYPAD = false; + + /** indicates whether the virtual keyboard is opened automatically */ + public static boolean USE_VIRTUAL_KEYBOARD_OPEN_AUTO = false; + + /** instance of the virtual keyboard listener */ + VirtualKeyboardListener vkl; + + // keyboard dimensions + int kbX; + int kbY; + int kbWidth; + int kbHeight; + int fontW; // width of 'M' + int fontH; // height of 'M' + int buttonW; // width of keyboard + int buttonH; // height of keyboard + int fontWCenter; // placement of text inside button + int fontHTop; // placement of text inside button + int maxRows; // horizontal keyboard rows + int maxColumns; // vertical keyboard columns + int fullColumns; // number of columns that are completely full with keys + int currentChar = 0; + int currentKeyboard = 1; // abc + int textfieldHeight = 0; // height of text field area, including adornments + int candidateFieldHeight = 0; // height of candidate input field + char itemIndexWhenPressed; + + char PRESS_OUT_OF_BOUNDS = 0; + + /** array of all available keys n the keyboard */ + char[][] keys; + + boolean inMetaKeys = false; // traversal mode + boolean inShift = false; + int currentMeta = 0; + Image[] metaKeys = null; + boolean textKbd = false; + Font f; + + static final int PRESSED = 0; + static final int RELEASED = 1; + + /** + * Virtual Keyboard constructor. + * + * @param keys array of available keys for the keyboard + * @param vkl the virtual keyboard listener + * @param displayTextArea flag to indicate whether to display the text area + */ + public VirtualKeyboard(char[][] keys, + VirtualKeyboardListener vkl, + boolean displayTextArea, + int neededColumns, + int neededRows) throws VirtualKeyboardException { + + textKbd = displayTextArea; + if (textKbd) { + PADDING = 1; + } else { + PADDING = 2; + } + + currentKeyboard = 0; + this.vkl = vkl; + + kbX = PADDING; + kbY = PADDING; + + kbWidth = vkl.getAvailableWidth() - 2 * PADDING; + kbHeight = vkl.getAvailableHeight() - 2 * PADDING; + + // f = Font.getFont(Font.MONOSPACED, // or SYSTEM + // Font.PLAIN, + // 36); + fontW = 36;// f.charWidth('M'); + fontH = 36;// f.getHeight(); + + if (textKbd) { + textfieldHeight = fontH + 8 * PADDING; + buttonW = fontW + 8; + buttonH = fontH + 8; + fontHTop = (buttonH - fontH) / 2; + fontWCenter = buttonW / 2; + } else { + buttonW = fontW * 3; + buttonH = fontH * 3; + fontHTop = (buttonH - fontH) / 2; + fontWCenter = buttonW / 2; + } + candidateFieldHeight = 0; + + maxRows = (kbHeight - PADDING) / (buttonH + PADDING); + + if (textKbd) { + if (neededColumns == 0) { + maxColumns = (kbWidth - PADDING) / (buttonW + PADDING); + } else { + maxColumns = neededColumns; + } + kbWidth = maxColumns * (buttonW + PADDING) + PADDING + 1; + kbX = (vkl.getAvailableWidth() - kbWidth) / 2; + } else { + maxColumns = 7; // verify + kbWidth = maxColumns * (buttonW + PADDING) + PADDING + 1; + kbX = 0; + + } + + if (neededRows == 0) { + int tmpMax = 0; // will hold the longest keyboard. + for (int i = 0; i < keys.length; i++) { + if (tmpMax < keys[i].length) + tmpMax = keys[i].length; + } + neededRows = (tmpMax + maxColumns - 1) / maxColumns; + } + if (neededRows > maxRows) { +System.err.println("Keys list is too long for this size of screen."); +System.err.println("Please split your keyboard array to multiple arrays."); + // System.exit(0); + throw new VirtualKeyboardException("Keys list is too long for this size of screen."); + } + maxRows = neededRows; + int neededHeight = 0; + // do not require to account for meta keys for a canvas keyboard-hk + if (textKbd) { + neededHeight = maxRows * (buttonH + PADDING) + 4 * PADDING + // between the keys and the meta keys + IMAGE_SIZE + META_PADDING * 4 + textfieldHeight + candidateFieldHeight; + kbY = kbHeight - neededHeight - 4 * PADDING; + kbHeight = neededHeight; + + } else { + neededHeight = maxRows * (buttonH + PADDING) + 3 * PADDING + textfieldHeight; + kbY = vkl.getAvailableHeight() - neededHeight; + kbHeight = neededHeight; + } + + this.keys = keys; + + if (textKbd) + currentKeyboard = 1; // lower case + else + currentKeyboard = 0; + fullColumns = keys[currentKeyboard].length / maxColumns; + // need not be displayed in the canvas mode + if (displayTextArea) { // hk + metaKeys = new Image[7]; + metaKeys[OK_META_KEY] = createImage("/ok.png"); + metaKeys[CANCEL_META_KEY] = createImage("/cancel.png"); + metaKeys[BACKSPACE_META_KEY] = createImage("/backspace.png"); + metaKeys[SHIFT_META_KEY] = createImage("/shift.png"); + metaKeys[CAPS_META_KEY] = createImage("/caps.png"); + metaKeys[MODE_META_KEY] = createImage("/mode.png"); +// metaKeys[CNINPUT_META_KEY] = createImage("cn.png"); + } + } + + private Image createImage(String name) { + Image image = Toolkit.getDefaultToolkit().getImage(getClass().getResource(name)); + return image; + } + + /** + * Checks if the virtual keyboard is enabled. + * + * @return true if the virtual keyboard is enabled, + * false otherwise. + */ + static boolean isKeyboardEnabled() { + return USE_VIRTUAL_KEYBOARD; + } + + /** + * Checks if the virtual keyboard is enabled. + * + * @return true if the virtual keyboard is enabled, + * false otherwise. + */ + static boolean isKeypadEnabled() { + return USE_VIRTUAL_KEYPAD; + } + + /** + * Checks if the virtual keyboard is opened automatically. + * + * @return true if the virtual keyboard is opened + * automatically, false otherwise. + */ + static boolean isAutoOpen() { + return USE_VIRTUAL_KEYBOARD_OPEN_AUTO; + } + + /** + * traverse the virtual keyboard according to key pressed. + * + * @param type type of keypress + * @param keyCode key code of key pressed + */ + void traverse(int type, int keyCode) { +System.err.println("VirtualK: keyCode=" + keyCode); + + // Soft button means dismiss to the virtual keyboard + if (type == RELEASED && keyCode == 461) { + vkl.virtualKeyEntered(type, (char) 0); + return; + } + + if (!inMetaKeys) { + if (type == RELEASED && + keyCode != KeyEvent.VK_ENTER) { + // in this case we don't want to traverse on key release + + } else { + switch (keyCode) { + case KeyEvent.VK_RIGHT: + currentChar++; + if (currentChar > keys[currentKeyboard].length - 1) { + currentChar = 0; + } + break; + case KeyEvent.VK_LEFT: + currentChar--; + if (currentChar < 0) { + currentChar = keys[currentKeyboard].length - 1; + } + break; + case KeyEvent.VK_UP: + currentChar = (currentChar - maxColumns); + if (currentChar < 0) { + currentChar = currentChar + (fullColumns + 1) * maxColumns; + if (currentChar > keys[currentKeyboard].length - 1) { + currentChar -= maxColumns; + } + } + break; + case KeyEvent.VK_DOWN: + currentChar = (currentChar + maxColumns); + if (currentChar > keys[currentKeyboard].length - 1) { + currentChar = (currentChar - maxColumns); + inMetaKeys = true; + } + break; + case KeyEvent.VK_ENTER: + // System.out.println("Key Selected - type :" + type + ", " + // + keys[currentKeyboard][currentChar]); + vkl.virtualKeyEntered(type, keys[currentKeyboard][currentChar]); + if (inShift && type == PRESSED) { + // shift is a one-shot upper case + inShift = false; + if (textKbd) { + currentKeyboard = 1; + vkl.virtualMetaKeyEntered(IM_CHANGED_KEY); + } // hk : still need a keyboard displayed + else { + currentKeyboard = 0; + } + } + break; + } + } + } else { + + if (type != RELEASED) { + + // meta keys + switch (keyCode) { + case KeyEvent.VK_RIGHT: + currentMeta++; + if (currentMeta > metaKeys.length - 1) { + currentMeta = 0; + } + break; + case KeyEvent.VK_LEFT: + currentMeta--; + if (currentMeta < 0) { + currentMeta = metaKeys.length - 1; + } + break; + case KeyEvent.VK_UP: + inMetaKeys = false; + break; + case KeyEvent.VK_DOWN: + inMetaKeys = false; + currentChar = (currentChar + maxColumns); + if (currentChar > keys[currentKeyboard].length - 1) { + currentChar = currentChar % maxColumns; + } + break; + case KeyEvent.VK_ENTER: + + switch (currentMeta) { + case SHIFT_META_KEY: // "Shift" - one shot upper case + if (currentKeyboard == 1) { // lower case + currentKeyboard = 2; + vkl.virtualMetaKeyEntered(IM_CHANGED_KEY); + } + inShift = true; + inMetaKeys = false; + break; + case CAPS_META_KEY: // "CapsL" (caps lock) + if (currentKeyboard == 1) { // lower case + currentKeyboard = 2; + } else if (currentKeyboard == 2) { // upper case + currentKeyboard = 1; + } + vkl.virtualMetaKeyEntered(IM_CHANGED_KEY); + break; + case MODE_META_KEY: // "Mode" + currentKeyboard = (currentKeyboard + 1) % keys.length; + vkl.virtualMetaKeyEntered(IM_CHANGED_KEY); + break; + case BACKSPACE_META_KEY: // "backspace" + vkl.virtualMetaKeyEntered(BACKSPACE_META_KEY); + break; + case OK_META_KEY: // "ok" + vkl.virtualMetaKeyEntered(OK_META_KEY); + break; + case CANCEL_META_KEY: // "cancel" + vkl.virtualMetaKeyEntered(CANCEL_META_KEY); + break; + case CNINPUT_META_KEY: // "cn_input" + vkl.virtualMetaKeyEntered(CNINPUT_META_KEY); + break; + } + } + } + } + + if (type != RELEASED) { + if (461 == keyCode) { + vkl.virtualMetaKeyEntered(BACKSPACE_META_KEY); + } else { + + switch (keyCode) { + // Short cuts by number keys + case 461: + vkl.virtualMetaKeyEntered(CNINPUT_META_KEY); + break; + case KeyEvent.VK_ENTER: + currentKeyboard = (currentKeyboard + 1) % keys.length; + vkl.virtualMetaKeyEntered(IM_CHANGED_KEY); + break; + case KeyEvent.VK_NUMPAD2: + vkl.virtualMetaKeyEntered(CURSOR_UP_META_KEY); + break; + case KeyEvent.VK_NUMPAD4: + vkl.virtualMetaKeyEntered(CURSOR_LEFT_META_KEY); + break; + case KeyEvent.VK_NUMPAD6: + vkl.virtualMetaKeyEntered(CURSOR_RIGHT_META_KEY); + break; + case KeyEvent.VK_NUMPAD8: + vkl.virtualMetaKeyEntered(CURSOR_DOWN_META_KEY); + break; + case KeyEvent.VK_NUMPAD5: + vkl.virtualMetaKeyEntered(CNINPUT_SELECT_META_KEY); + break; + } + } + } + // triggers paint() + vkl.repaintVK(); + } + + /** + * paint the virtual keyboard on the screen + * + * @param g The graphics context to paint to + */ + protected void paint(Graphics g) { + int actualHeight = kbHeight + candidateFieldHeight; + g.setFont(f); + g.setColor(Color.lightGray); + + g.fillRect(0, 0, kbWidth, actualHeight); + drawBorder(g, 0, 0, kbWidth - 1, actualHeight - 1); + + if (candidateFieldHeight > 0) { + drawCandidateBar(g); + } + + g.translate(0, candidateFieldHeight); + + if (textfieldHeight > 0) { + drawTextField(g); + } + + g.translate(0, textfieldHeight); + drawKeys(g); + + g.translate(0, actualHeight - (IMAGE_SIZE + 4 * PADDING + 2 * META_PADDING) - textfieldHeight - candidateFieldHeight); + if (textKbd) { + drawMetaKeys(g); + } + } + + /** + * Draw the text field of the virtual keyboard. + * + * @param g The graphics context to paint to + */ + void drawTextField(Graphics g) { + drawSunkedBorder(g, PADDING, PADDING, kbWidth - 2 * PADDING, textfieldHeight); + + g.setClip(0, 0, kbWidth - 2 * PADDING, textfieldHeight); + + g.translate(PADDING + 1, 0); + + vkl.paintTextOnly(g, kbWidth, textfieldHeight); + + g.translate(-PADDING - 1, 0); + g.setClip(0, 0, kbWidth, kbHeight); + } + + void drawCandidateBar(Graphics g) { + + g.setClip(0, 0, kbWidth - 2 * PADDING, candidateFieldHeight); + + g.translate(PADDING + 1, 2 * PADDING); + + vkl.paintCandidateBar(g, kbWidth - 3 * PADDING, candidateFieldHeight - 2 * PADDING); + + g.translate(-PADDING - 1, -PADDING); + g.setClip(0, 0, kbWidth, kbHeight); + } + + /** + * draw keyboard keys + * + * @param g The graphics context to paint to + */ + void drawKeys(Graphics g) { + + int tmp; + + if (!textKbd) { + currentKeyboard = 0; + } + + for (int i = 0; i < maxRows; i++) { + for (int j = 0; j < maxColumns; j++) { + tmp = i * maxColumns + j; + if (tmp >= keys[currentKeyboard].length) { + // no more chars to draw + break; + } + + if (currentChar == tmp && inMetaKeys == false) { + + drawButton(g, j * (PADDING + buttonW) + PADDING, i * (PADDING + buttonH) + PADDING, buttonW, buttonH); + } else { + drawBeveledButton(g, j * (PADDING + buttonW) + PADDING, i * (PADDING + buttonH) + PADDING, buttonW, buttonH); + } + + // g.setColor(DARK_GRAY); + g.setColor(TEXT_COLOR); + g.drawString("" + keys[currentKeyboard][tmp], j * (PADDING + buttonW) + PADDING + fontWCenter, i * (PADDING + buttonH) + PADDING + fontHTop); + } + } + } + + /** + * draw keyboard meta keys + * + * @param g The graphics context to paint to + */ + void drawMetaKeys(Graphics g) { + + int mkWidth = metaKeys.length * (IMAGE_SIZE + 3 * META_PADDING) + META_PADDING; + int currX = (kbWidth - mkWidth) / 2 + 2 * META_PADDING; + int currY = 0; + + if (inMetaKeys) { + drawBorder(g, currX - 2 * META_PADDING, // x1 + currY - 2 * META_PADDING, // y1 + currX + mkWidth, + currY + IMAGE_SIZE + 2 * META_PADDING); + } + + for (int i = 0; i < metaKeys.length; i++) { + if (currX + IMAGE_SIZE > kbWidth) { + + currX = PADDING; + currY -= (IMAGE_SIZE + META_PADDING); + } + if (inMetaKeys && i == currentMeta) { + drawButton(g, currX, currY, IMAGE_SIZE + 2 * META_PADDING, IMAGE_SIZE + 2 * META_PADDING); + } else { + drawBeveledButton(g, currX, currY, IMAGE_SIZE + 2 * META_PADDING, IMAGE_SIZE + 2 * META_PADDING); + } + g.drawImage(metaKeys[i], currX + META_PADDING, currY + META_PADDING, null); + currX += (IMAGE_SIZE + 2 * META_PADDING + 2); + if (currX > kbWidth) { + currX = META_PADDING; + currY -= (IMAGE_SIZE + META_PADDING); + } + } + } + + /** + * draw a border + * + * @param g The graphics context to paint to + * @param x1 x-coordinate of the button's location + * @param y1 y-coordinate of the button's location + * @param x2 the x-coordinate at the width of the border + * @param y2 the y-coordinate at the height of the border + */ + private void drawBorder(Graphics g, int x1, int y1, int x2, int y2) { + + g.setColor(Color.gray); + g.drawLine(x1 + 2, y1 + 2, x1 + 2, y2 - 3); // left + g.drawLine(x1 + 2, y1 + 2, x2 - 2, y1 + 2); // top + g.drawLine(x1 + 2, y2 - 1, x2 - 1, y2 - 1); // bottom + g.drawLine(x2 - 1, y1 + 2, x2 - 1, y2 - 1); // right + g.setColor(Color.white); + g.drawRect(x1 + 1, y1 + 1, x2 - x1 - 3, y2 - y1 - 3); + } + + /** + * draw a sunken border + * + * @param g The graphics context to paint to + * @param x1 x-coordinate of the button's location + * @param y1 y-coordinate of the button's location + * @param x2 the x-coordinate at the width of the border + * @param y2 the y-coordinate at the height of the border + */ + private void drawSunkedBorder(Graphics g, int x1, int y1, int x2, int y2) { + + g.setColor(Color.white); + g.fillRect(x1 + 2, y1 + 2, x2 - x1 - 2, y2 - y1 - 2); + + g.setColor(Color.gray); + g.drawLine(x1 + 2, y1 + 2, x1 + 2, y2 - 2); // left + g.drawLine(x1 + 2, y1 + 2, x2 - 2, y1 + 2); // top + g.setColor(Color.darkGray); + g.drawLine(x1 + 3, y1 + 3, x1 + 3, y2 - 3); // left + g.drawLine(x1 + 3, y1 + 3, x2 - 3, y1 + 3); // top + + g.setColor(Color.lightGray); + g.drawLine(x1 + 3, y2 - 2, x2 - 2, y2 - 2); // bottom + g.drawLine(x2 - 2, y1 + 3, x2 - 2, y2 - 2); // right + } + + /** + * draw a button + * + * @param g The graphics context to paint to + * @param x x-coordinate of the button's location + * @param y y-coordinate of the button's location + * @param w the width of the button + * @param h the height of the button + */ + private void drawButton(Graphics g, int x, int y, int w, int h) { + g.setColor(Color.gray); + g.drawLine(x + 1, y + h - 1, x + w, y + h - 1); // bottom + g.drawLine(x + w - 1, y + 1, x + w - 1, y + h); // right + + g.setColor(Color.darkGray); + g.drawLine(x, y + h, x + w, y + h); // bottom + g.drawLine(x + w, y, x + w, y + h); // right + + g.setColor(Color.white); + g.drawLine(x, y, x + w - 1, y); + g.drawLine(x, y, x, y + h - 1); + + } + + /** + * draw a beveled button + * + * @param g The graphics context to paint to + * @param x x-coordinate of the button's location + * @param y y-coordinate of the button's location + * @param w the width of the button + * @param h the height of the button + */ + private void drawBeveledButton(Graphics g, int x, int y, int w, int h) { + g.setColor(Color.gray); + g.drawLine(x + 1, y + h - 1, x + w, y + h - 1); // bottom + g.drawLine(x + w - 1, y + 1, x + w - 1, y + h); // right + + g.setColor(Color.white); + g.drawLine(x, y + h, x + w, y + h); // bottom + g.drawLine(x + w, y, x + w, y + h); // right + + g.setColor(Color.gray); + g.drawLine(x, y, x + w - 1, y); + g.drawLine(x, y, x, y + h - 1); + + g.setColor(Color.white); + g.drawLine(x + 1, y + 1, x + w - 2, y + 1); + g.drawLine(x + 1, y + 1, x + 1, y + h - 2); + + } + + /** + * Helper function to determine the itemIndex at the x,y position + * + * @param x,y pointer coordinates in menuLayer's space (0,0 means left-top + * corner) both value can be negative as menuLayer handles the + * pointer event outside its bounds + * @return menuItem's index since 0, or PRESS_OUT_OF_BOUNDS, PRESS_ON_TITLE + * + */ + private boolean isKeyAtPointerPosition(int x, int y) { + int tmpX, tmpY, tmp; + for (int i = 0; i < maxRows; i++) { + for (int j = 0; j < maxColumns; j++) { + tmp = i * maxColumns + j; + if (tmp >= keys[currentKeyboard].length) { + // no more chars to draw + break; + } + + tmpX = x - (j * (PADDING + buttonW) + PADDING); + tmpY = y - (i * (PADDING + buttonH) + PADDING) - textfieldHeight; + + if ((tmpX >= 0) && (tmpY >= 0) && (tmpX < buttonW) && (tmpY < buttonH)) { + currentChar = tmp; + inMetaKeys = false; + return true; + } + + } + } + + if (metaKeys == null) { + return false; + } + + // Check for meta chars + int mkWidth = metaKeys.length * (IMAGE_SIZE + 3 * META_PADDING) + META_PADDING; + int currX = (kbWidth - mkWidth) / 2 + 2 * META_PADDING; + int currY = kbHeight - (IMAGE_SIZE + 6 * META_PADDING); + + for (int i = 0; i < metaKeys.length; i++) { + if (currX + IMAGE_SIZE > kbWidth) { + + currX = PADDING; + currY -= (IMAGE_SIZE + META_PADDING); + } + + tmpX = x - currX; + tmpY = y - currY; + + if ((tmpX >= 0) && (tmpY >= 0) && (tmpX < (IMAGE_SIZE + 2 * META_PADDING)) && (tmpY < (IMAGE_SIZE + 2 * META_PADDING))) { + currentMeta = i; + inMetaKeys = true; + return true; + } + + currX += (IMAGE_SIZE + 2 * META_PADDING + 2); + if (currX > kbWidth) { + currX = META_PADDING; + currY -= (IMAGE_SIZE + META_PADDING); + } + } + + return false; + } + + /** + * Handle input from a pen tap. Parameters describe the type of pen event + * and the x,y location in the layer at which the event occurred. Important + * : the x,y location of the pen tap will already be translated into the + * coordinate space of the layer. + * + * @param type the type of pen event + * @param x the x coordinate of the event + * @param y the y coordinate of the event + */ + public boolean pointerInput(int type, int x, int y) { + switch (type) { + case PRESSED: + + // dismiss the menu layer if the user pressed outside the menu + if (isKeyAtPointerPosition(x, y)) { + // press on valid key + traverse(type, KeyEvent.VK_ENTER); + vkl.repaintVK(); + + } + break; + case RELEASED: + if (isKeyAtPointerPosition(x, y)) { + traverse(type, KeyEvent.VK_ENTER); + vkl.repaintVK(); + + } + + break; + } + // return true always as menuLayer will capture all of the pointer + // inputs + return true; + } + + // ********* attributes ********* // + + private final static Color TEXT_COLOR = Color.black; + + /** padding between rows of buttons */ + private int PADDING; + + /** padding used by the meta keys */ + private final static int META_PADDING = 2; + + /** size of meta icons */ + private final static int IMAGE_SIZE = 13; + + // If you want to change the order of the buttons, just + // change the serial numbers here: + final static int OK_META_KEY = 0; + final static int CANCEL_META_KEY = 1; + final static int MODE_META_KEY = 2; + final static int BACKSPACE_META_KEY = 3; + final static int SHIFT_META_KEY = 4; + final static int CAPS_META_KEY = 5; + final static int CNINPUT_META_KEY = 6; + final static int CURSOR_UP_META_KEY = 7; + final static int CURSOR_DOWN_META_KEY = 8; + final static int CURSOR_LEFT_META_KEY = 9; + final static int CURSOR_RIGHT_META_KEY = 10; + final static int CNINPUT_SELECT_META_KEY = 11; + + // When input method is changed, process this key to update UI + final static int IM_CHANGED_KEY = 99; + +} + +class VirtualKeyboardException extends Exception { + /** + * Constructs an IOException with null as its + * error detail message. + */ + public VirtualKeyboardException() { + super(); + } + + /** + * Constructs an IOException with the specified detail message. + * The error message string s can later be retrieved by the + * {@link java.lang.Throwable#getMessage} method of class + * java.lang.Throwable. + * + * @param s the detail message. + */ + public VirtualKeyboardException(String s) { + super(s); + } +} diff --git a/src/test/java/vavi/apps/appleii/VirtualKeyboardListener.java b/src/test/java/vavi/apps/appleii/VirtualKeyboardListener.java new file mode 100644 index 0000000..65eff02 --- /dev/null +++ b/src/test/java/vavi/apps/appleii/VirtualKeyboardListener.java @@ -0,0 +1,55 @@ +/* + * $LastChangedDate: 2005-09-18 20:31:12 +0900 (ì¼, 18 9 2005) $ + * + * Copyright 1990-2006 Sun Microsystems, Inc. All rights reserved. + * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ + +package vavi.apps.appleii; + +import java.awt.Graphics; + + +/** + * This interface should be implemented by a client that needs a popup keyboard. + * @author Amir Uval + */ +interface VirtualKeyboardListener { + + /** + * key input callback + */ + public void virtualKeyEntered(int type, char c); + + /** + * meta key event callback + */ + public void virtualMetaKeyEntered(int metaKey); + + /** + * a callback used to draw the text entered by the virtual keyboard - on the + * keyboard text area. + * In KeyboardLayer, it is implemented by passing the call to + * TextField's paint(..) + */ + public void paintTextOnly(Graphics g, int width, int height); + + public void paintCandidateBar(Graphics g, int width, int height); + + /** + * should return the width of the owner Displayable + */ + public int getAvailableWidth(); + + /** + * should return the height of the owner Displayable + */ + public int getAvailableHeight(); + + /** + * should trigger a requestRepaint() call to schedule a + * paint() of the VirtualKeyboard + */ + public void repaintVK(); +} + diff --git a/src/test/java/vavi/apps/appleii/VirtualKeyboardTest.java b/src/test/java/vavi/apps/appleii/VirtualKeyboardTest.java new file mode 100644 index 0000000..8d4adb6 --- /dev/null +++ b/src/test/java/vavi/apps/appleii/VirtualKeyboardTest.java @@ -0,0 +1,391 @@ +/* + * Copyright (c) 2008 by Naohide Sano, All rights reserved. + * + * Programmed by Naohide Sano + */ + +package vavi.apps.appleii; + +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Dialog; +import java.awt.Graphics; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import junit.framework.TestCase; + + +/** + * VirtualKeyboardTest. + * + * @author Naohide Sano (nsano) + * @version 0.00 080924 nsano initial version
+ */ +public class VirtualKeyboardTest extends TestCase { + + public void test01() throws Exception { + char[][] keys = null; + int neededColumns; + int neededRows; + + keys = new char[4][]; + + // numerals + keys[0] = new char[23]; // numerals + for (char i=0; i<10; i++) { // 0..9 + keys[0][i] = (char)(i+48); + } + keys[0][10] = '='; + keys[0][11] = '+'; + keys[0][12] = '-'; + keys[0][13] = '*'; + keys[0][14] = '/'; + keys[0][15] = '.'; + keys[0][16] = ','; + keys[0][17] = '$'; + keys[0][18] = '%'; + keys[0][19] = '^'; + keys[0][20] = '#'; + keys[0][21] = '_'; + keys[0][22] = ' '; + + // Roman, lower case + keys[1] = new char[51]; // numerals + keys[1][0] = 'q'; + keys[1][1] = 'w'; + keys[1][2] = 'e'; + keys[1][3] = 'r'; + keys[1][4] = 't'; + keys[1][5] = 'y'; + keys[1][6] = 'u'; + keys[1][7] = 'i'; + keys[1][8] = 'o'; + keys[1][9] = 'p'; + keys[1][10] = '1'; + keys[1][11] = '2'; + keys[1][12] = '3'; + keys[1][13] = '0'; + keys[1][14] = '!'; + keys[1][15] = '@'; + keys[1][16] = '#'; + keys[1][17] = 'a'; + keys[1][18] = 's'; + keys[1][19] = 'd'; + keys[1][20] = 'f'; + keys[1][21] = 'g'; + keys[1][22] = 'h'; + keys[1][23] = 'j'; + keys[1][24] = 'k'; + keys[1][25] = 'l'; + keys[1][26] = ';'; + keys[1][27] = '4'; + keys[1][28] = '5'; + keys[1][29] = '6'; + keys[1][30] = '_'; + keys[1][31] = '$'; + keys[1][32] = '%'; + keys[1][33] = '^'; + keys[1][34] = 'z'; + keys[1][35] = 'x'; + keys[1][36] = 'c'; + keys[1][37] = 'v'; + keys[1][38] = 'b'; + keys[1][39] = 'n'; + keys[1][40] = 'm'; + keys[1][41] = ','; + keys[1][42] = '.'; + keys[1][43] = ' ';// space + keys[1][44] = '7'; + keys[1][45] = '8'; + keys[1][46] = '9'; + keys[1][47] = '?'; + keys[1][48] = '&'; + keys[1][49] = '*'; + keys[1][50] = '/'; + + // Roman, upper case + keys[2] = new char[51]; // numerals + keys[2][0] = 'Q'; + keys[2][1] = 'W'; + keys[2][2] = 'E'; + keys[2][3] = 'R'; + keys[2][4] = 'T'; + keys[2][5] = 'Y'; + keys[2][6] = 'U'; + keys[2][7] = 'I'; + keys[2][8] = 'O'; + keys[2][9] = 'P'; + keys[2][10] = '1'; + keys[2][11] = '2'; + keys[2][12] = '3'; + keys[2][13] = '0'; + keys[2][14] = '!'; + keys[2][15] = '@'; + keys[2][16] = '#'; + keys[2][17] = 'A'; + keys[2][18] = 'S'; + keys[2][19] = 'D'; + keys[2][20] = 'F'; + keys[2][21] = 'G'; + keys[2][22] = 'H'; + keys[2][23] = 'J'; + keys[2][24] = 'K'; + keys[2][25] = 'L'; + keys[2][26] = ';'; + keys[2][27] = '4'; + keys[2][28] = '5'; + keys[2][29] = '6'; + keys[2][30] = '_'; + keys[2][31] = '$'; + keys[2][32] = '%'; + keys[2][33] = '^'; + keys[2][34] = 'Z'; + keys[2][35] = 'X'; + keys[2][36] = 'C'; + keys[2][37] = 'V'; + keys[2][38] = 'B'; + keys[2][39] = 'N'; + keys[2][40] = 'M'; + keys[2][41] = ','; + keys[2][42] = '.'; + keys[2][43] = ' ';// space + keys[2][44] = '7'; + keys[2][45] = '8'; + keys[2][46] = '9'; + keys[2][47] = '?'; + keys[2][48] = '&'; + keys[2][49] = '*'; + keys[2][50] = '/'; + + // Symbol + keys[3] = new char[25]; // numerals + for (char i=0; i<15; i++) { // !../ + keys[3][i] = (char)(i+33); + } + for (char i=0; i<7; i++) { // :..@ + keys[3][i+15] = (char)(i+58); + } + keys[3][22] = '~'; // space + keys[3][23] = '^'; // space + keys[3][24] = ' '; // space + + neededColumns = 17; + neededRows = 3; + + VirtualKeyboardListener vkl = new VirtualKeyboardListener() { + public int getAvailableHeight() { + return 640; + } + public int getAvailableWidth() { + return 400; + } + public void paintCandidateBar(Graphics g, int width, int height) { + g.setColor(Color.pink); + g.fillRect(0, 0, width, height); + } + public void paintTextOnly(Graphics g, int width, int height) { + g.setColor(Color.blue); + g.fillRect(0, 0, width, height); + } + public void repaintVK() { + } + public void virtualKeyEntered(int type, char c) { + } + public void virtualMetaKeyEntered(int metaKey) { + } + }; + + Dialog dialog = new Dialog(null, true); + final VirtualKeyboard virtualKeyboard = new VirtualKeyboard(keys, vkl, true, neededColumns, neededRows); + Canvas canvas = new Canvas() { + public void paint(Graphics g) { + virtualKeyboard.paint(g); + super.paint(g); + } + }; + canvas.setSize(640, 400); + dialog.add(canvas); + dialog.pack(); + dialog.show(); + } + + public void $test02() throws Exception { + byte[][] bs = { + ok, + cancel, + backspace, + shift, + caps, + mode, + cn + }; + String[] names = { + "ok.png", + "cancel.png", + "backspace.png", + "shift.png", + "caps.png", + "mode.png", + "cn.png" + }; + for (int i = 0; i < names.length; i++) { + x(names[i], bs[i]); + } + } + + private void x(String name, byte[] b) throws IOException { + OutputStream os = new FileOutputStream(name); + os.write(b, 0, b.length); + os.flush(); + os.close(); + } + + /** backspace.png */ + private byte[] backspace = { + (byte) 0x89, (byte) 0x50, (byte) 0x4e, (byte) 0x47, (byte) 0x0d, (byte) 0x0a, (byte) 0x1a, (byte) 0x0a, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0d, (byte) 0x49, (byte) 0x48, (byte) 0x44, (byte) 0x52, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0d, (byte) 0x08, (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x45, (byte) 0x35, (byte) 0x14, (byte) 0x4e, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x04, (byte) 0x67, + (byte) 0x41, (byte) 0x4d, (byte) 0x41, (byte) 0x00, (byte) 0x00, (byte) 0xb1, (byte) 0x8e, (byte) 0x7c, (byte) 0xfb, (byte) 0x51, (byte) 0x93, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x20, (byte) 0x63, (byte) 0x48, (byte) 0x52, (byte) 0x4d, (byte) 0x00, (byte) 0x00, (byte) 0x7a, (byte) 0x25, (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x83, (byte) 0x00, (byte) 0x00, (byte) 0xf9, (byte) 0xff, (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0xe6, (byte) 0x00, (byte) 0x00, (byte) 0x75, + (byte) 0x2e, (byte) 0x00, (byte) 0x00, (byte) 0xea, (byte) 0x5f, (byte) 0x00, (byte) 0x00, (byte) 0x3a, (byte) 0x97, (byte) 0x00, (byte) 0x00, (byte) 0x17, (byte) 0x6f, (byte) 0x69, (byte) 0xe4, (byte) 0xc4, (byte) 0x2b, (byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0x00, (byte) 0x50, (byte) 0x4c, (byte) 0x54, (byte) 0x45, (byte) 0xe6, (byte) 0xe6, (byte) 0xe6, (byte) 0xcc, (byte) 0xcc, (byte) 0xcc, (byte) 0xa6, (byte) 0xa6, (byte) 0xa6, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x1b, (byte) 0xff, (byte) 0xdb, (byte) 0xbb, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x05, (byte) 0x74, (byte) 0x52, (byte) 0x4e, (byte) 0x53, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00, (byte) 0xfb, (byte) 0xb6, (byte) 0x0e, (byte) 0x53, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0x49, (byte) 0x44, (byte) 0x41, (byte) 0x54, (byte) 0x78, (byte) 0x9c, (byte) 0x62, (byte) 0x60, (byte) 0x41, (byte) 0x06, (byte) 0x00, (byte) 0x01, (byte) 0xc4, (byte) 0x80, (byte) 0xc2, (byte) 0x03, (byte) 0x08, (byte) 0x20, + (byte) 0x30, (byte) 0x8f, (byte) 0x11, (byte) 0x0a, (byte) 0x98, (byte) 0x01, (byte) 0x02, (byte) 0x08, (byte) 0xc4, (byte) 0x63, (byte) 0x64, (byte) 0x80, (byte) 0x02, (byte) 0x66, (byte) 0x80, (byte) 0x00, (byte) 0x62, (byte) 0x00, (byte) 0x73, (byte) 0x98, (byte) 0x81, (byte) 0x4c, (byte) 0x26, (byte) 0x20, (byte) 0x05, (byte) 0x10, (byte) 0x40, (byte) 0x0c, (byte) 0x10, (byte) 0x19, (byte) 0x66, (byte) 0x10, (byte) 0x87, (byte) 0x81, (byte) 0x19, (byte) 0x20, (byte) 0x80, (byte) 0x18, + (byte) 0x18, (byte) 0x61, (byte) 0x8a, (byte) 0x40, (byte) 0x04, (byte) 0x40, (byte) 0x00, (byte) 0x31, (byte) 0xb0, (byte) 0x80, (byte) 0x69, (byte) 0x26, (byte) 0x30, (byte) 0x97, (byte) 0x19, (byte) 0x20, (byte) 0x80, (byte) 0x80, (byte) 0xfa, (byte) 0x98, (byte) 0x19, (byte) 0xa0, (byte) 0xca, (byte) 0x18, (byte) 0x98, (byte) 0x01, (byte) 0x02, (byte) 0x08, (byte) 0x64, (byte) 0x26, (byte) 0x33, (byte) 0xdc, (byte) 0x4c, (byte) 0x80, (byte) 0x00, (byte) 0x02, (byte) 0xdb, (byte) 0x07, + (byte) 0xe3, (byte) 0x32, (byte) 0x03, (byte) 0x04, (byte) 0x10, (byte) 0xc4, (byte) 0x2d, (byte) 0xcc, (byte) 0x50, (byte) 0x00, (byte) 0x10, (byte) 0x40, (byte) 0xa8, (byte) 0x2e, (byte) 0x03, (byte) 0x08, (byte) 0x30, (byte) 0x00, (byte) 0x82, (byte) 0x47, (byte) 0x01, (byte) 0x63, (byte) 0x1f, (byte) 0x9e, (byte) 0x42, (byte) 0x65, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x49, (byte) 0x45, (byte) 0x4e, (byte) 0x44, (byte) 0xae, (byte) 0x42, (byte) 0x60, (byte) 0x82 + }; + + /** cancel.png */ + private byte[] cancel = { + (byte) 0x89, (byte) 0x50, (byte) 0x4e, (byte) 0x47, (byte) 0x0d, (byte) 0x0a, (byte) 0x1a, (byte) 0x0a, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0d, (byte) 0x49, (byte) 0x48, (byte) 0x44, (byte) 0x52, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0d, (byte) 0x08, (byte) 0x06, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x05, (byte) 0xec, (byte) 0xd4, (byte) 0xea, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x04, (byte) 0x67, + (byte) 0x41, (byte) 0x4d, (byte) 0x41, (byte) 0x00, (byte) 0x00, (byte) 0xaf, (byte) 0xc8, (byte) 0x37, (byte) 0x05, (byte) 0x8a, (byte) 0xe9, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x19, (byte) 0x74, (byte) 0x45, (byte) 0x58, (byte) 0x74, (byte) 0x53, (byte) 0x6f, (byte) 0x66, (byte) 0x74, (byte) 0x77, (byte) 0x61, (byte) 0x72, (byte) 0x65, (byte) 0x00, (byte) 0x41, (byte) 0x64, (byte) 0x6f, (byte) 0x62, (byte) 0x65, (byte) 0x20, (byte) 0x49, (byte) 0x6d, (byte) 0x61, (byte) 0x67, + (byte) 0x65, (byte) 0x52, (byte) 0x65, (byte) 0x61, (byte) 0x64, (byte) 0x79, (byte) 0x71, (byte) 0xc9, (byte) 0x65, (byte) 0x3c, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x05, (byte) 0x49, (byte) 0x44, (byte) 0x41, (byte) 0x54, (byte) 0x78, (byte) 0xda, (byte) 0x62, (byte) 0xfc, (byte) 0xff, (byte) 0xff, (byte) 0x3f, (byte) 0x03, (byte) 0x08, (byte) 0x00, (byte) 0x04, (byte) 0x10, (byte) 0x03, (byte) 0x88, (byte) 0xc1, (byte) 0xc4, (byte) 0xc4, (byte) 0xf4, (byte) 0x1e, (byte) 0x20, + (byte) 0x80, (byte) 0x18, (byte) 0x61, (byte) 0x22, (byte) 0x00, (byte) 0x01, (byte) 0x04, (byte) 0xe6, (byte) 0x81, (byte) 0x38, (byte) 0x00, (byte) 0x01, (byte) 0x04, (byte) 0x93, (byte) 0xfa, (byte) 0x0f, (byte) 0xc2, (byte) 0x20, (byte) 0x36, (byte) 0x40, (byte) 0x00, (byte) 0x21, (byte) 0x94, (byte) 0x40, (byte) 0x01, (byte) 0x40, (byte) 0x00, (byte) 0xa1, (byte) 0x08, (byte) 0x00, (byte) 0x04, (byte) 0x10, (byte) 0x23, (byte) 0x50, (byte) 0x19, (byte) 0x9c, (byte) 0x03, (byte) 0x10, + (byte) 0x40, (byte) 0x2c, (byte) 0x50, (byte) 0x5a, (byte) 0x00, (byte) 0x88, (byte) 0x0d, (byte) 0x00, (byte) 0x02, (byte) 0x08, (byte) 0x45, (byte) 0x19, (byte) 0x40, (byte) 0x00, (byte) 0xc1, (byte) 0x4c, (byte) 0x05, (byte) 0xe1, (byte) 0x7a, (byte) 0x28, (byte) 0x0d, (byte) 0xc6, (byte) 0x20, (byte) 0x71, (byte) 0x80, (byte) 0x00, (byte) 0x02, (byte) 0xab, (byte) 0x64, (byte) 0x66, (byte) 0x66, (byte) 0x86, (byte) 0xab, (byte) 0x05, (byte) 0x99, (byte) 0x0b, (byte) 0x62, (byte) 0xfc, + (byte) 0xfd, (byte) 0xfb, (byte) 0x97, (byte) 0x01, (byte) 0x20, (byte) 0x80, (byte) 0x30, (byte) 0xac, (byte) 0x47, (byte) 0x06, (byte) 0x00, (byte) 0x01, (byte) 0x84, (byte) 0x53, (byte) 0x12, (byte) 0x20, (byte) 0x80, (byte) 0x60, (byte) 0xf6, (byte) 0x09, (byte) 0x20, (byte) 0xd9, (byte) 0x65, (byte) 0x00, (byte) 0xa2, (byte) 0x01, (byte) 0x02, (byte) 0x88, (byte) 0x09, (byte) 0xc9, (byte) 0x89, (byte) 0xfd, (byte) 0x40, (byte) 0xbc, (byte) 0x1f, (byte) 0xe4, (byte) 0x54, (byte) 0x90, + (byte) 0x00, (byte) 0x40, (byte) 0x00, (byte) 0xc1, (byte) 0x24, (byte) 0x1e, (byte) 0x00, (byte) 0xb1, (byte) 0x02, (byte) 0x10, (byte) 0x1f, (byte) 0x00, (byte) 0xe2, (byte) 0x05, (byte) 0x20, (byte) 0x01, (byte) 0x80, (byte) 0x00, (byte) 0x82, (byte) 0x79, (byte) 0xca, (byte) 0x01, (byte) 0xaa, (byte) 0x2b, (byte) 0x00, (byte) 0xca, (byte) 0x9f, (byte) 0x08, (byte) 0x10, (byte) 0x40, (byte) 0x38, (byte) 0x2d, (byte) 0x07, (byte) 0x08, (byte) 0x20, (byte) 0x26, (byte) 0x5c, (byte) 0xce, + (byte) 0x05, (byte) 0x08, (byte) 0x20, (byte) 0xbc, (byte) 0x7e, (byte) 0xc1, (byte) 0x05, (byte) 0x00, (byte) 0x02, (byte) 0x08, (byte) 0xec, (byte) 0x15, (byte) 0xb4, (byte) 0xe0, (byte) 0xfb, (byte) 0x8f, (byte) 0xe4, (byte) 0x35, (byte) 0x10, (byte) 0xbd, (byte) 0x1f, (byte) 0x2a, (byte) 0x56, (byte) 0x00, (byte) 0x0b, (byte) 0x52, (byte) 0x80, (byte) 0x00, (byte) 0x42, (byte) 0xd7, (byte) 0x04, (byte) 0xc2, (byte) 0x09, (byte) 0x50, (byte) 0x45, (byte) 0x30, (byte) 0xc5, (byte) 0x01, + (byte) 0xe8, (byte) 0xf1, (byte) 0x00, (byte) 0x10, (byte) 0x40, (byte) 0xd8, (byte) 0xdc, (byte) 0x7d, (byte) 0x01, (byte) 0x88, (byte) 0x3f, (byte) 0x40, (byte) 0xc3, (byte) 0xe8, (byte) 0x03, (byte) 0x34, (byte) 0x78, (byte) 0x50, (byte) 0x00, (byte) 0x40, (byte) 0x00, (byte) 0x21, (byte) 0xdb, (byte) 0x04, (byte) 0xb2, (byte) 0xe1, (byte) 0x3d, (byte) 0x10, (byte) 0xaf, (byte) 0x47, (byte) 0x0b, (byte) 0xf9, (byte) 0x7e, (byte) 0xa8, (byte) 0x8d, (byte) 0xeb, (byte) 0x61, (byte) 0x36, + (byte) 0x01, (byte) 0x04, (byte) 0x10, (byte) 0x59, (byte) 0x01, (byte) 0x01, (byte) 0x10, (byte) 0x60, (byte) 0x00, (byte) 0x1b, (byte) 0x87, (byte) 0x6f, (byte) 0x18, (byte) 0x70, (byte) 0x09, (byte) 0x02, (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x49, (byte) 0x45, (byte) 0x4e, (byte) 0x44, (byte) 0xae, (byte) 0x42, (byte) 0x60, (byte) 0x82 + }; + + /** caps.png */ + private byte[] caps = { + (byte) 0x89, (byte) 0x50, (byte) 0x4e, (byte) 0x47, (byte) 0x0d, (byte) 0x0a, (byte) 0x1a, (byte) 0x0a, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0d, (byte) 0x49, (byte) 0x48, (byte) 0x44, (byte) 0x52, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0d, (byte) 0x08, (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x45, (byte) 0x35, (byte) 0x14, (byte) 0x4e, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x04, (byte) 0x67, + (byte) 0x41, (byte) 0x4d, (byte) 0x41, (byte) 0x00, (byte) 0x00, (byte) 0xb1, (byte) 0x8e, (byte) 0x7c, (byte) 0xfb, (byte) 0x51, (byte) 0x93, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x20, (byte) 0x63, (byte) 0x48, (byte) 0x52, (byte) 0x4d, (byte) 0x00, (byte) 0x00, (byte) 0x7a, (byte) 0x25, (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x83, (byte) 0x00, (byte) 0x00, (byte) 0xf9, (byte) 0xff, (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0xe6, (byte) 0x00, (byte) 0x00, (byte) 0x75, + (byte) 0x2e, (byte) 0x00, (byte) 0x00, (byte) 0xea, (byte) 0x5f, (byte) 0x00, (byte) 0x00, (byte) 0x3a, (byte) 0x97, (byte) 0x00, (byte) 0x00, (byte) 0x17, (byte) 0x6f, (byte) 0x69, (byte) 0xe4, (byte) 0xc4, (byte) 0x2b, (byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0x00, (byte) 0x50, (byte) 0x4c, (byte) 0x54, (byte) 0x45, (byte) 0xe6, (byte) 0xe6, (byte) 0xe6, (byte) 0xcc, (byte) 0xcc, (byte) 0xcc, (byte) 0x7d, (byte) 0x7d, (byte) 0x7d, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xa0, (byte) 0xe5, (byte) 0xcc, (byte) 0x14, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x04, (byte) 0x74, (byte) 0x52, (byte) 0x4e, (byte) 0x53, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00, (byte) 0x40, (byte) 0x2a, (byte) 0xa9, (byte) 0xf4, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x65, (byte) 0x49, (byte) 0x44, (byte) 0x41, (byte) 0x54, (byte) 0x78, (byte) 0x9c, (byte) 0x62, (byte) 0x60, (byte) 0x06, (byte) 0x03, (byte) 0x46, (byte) 0x08, (byte) 0x05, (byte) 0x10, (byte) 0x40, (byte) 0x0c, (byte) 0x10, (byte) 0x0e, (byte) 0x03, + (byte) 0x13, (byte) 0x98, (byte) 0x06, (byte) 0x08, (byte) 0x20, (byte) 0x06, (byte) 0x08, (byte) 0x87, (byte) 0x01, (byte) 0xc2, (byte) 0x05, (byte) 0x08, (byte) 0x20, (byte) 0x06, (byte) 0x28, (byte) 0x07, (byte) 0xc2, (byte) 0x05, (byte) 0x08, (byte) 0x20, (byte) 0x06, (byte) 0x18, (byte) 0x07, (byte) 0xcc, (byte) 0x05, (byte) 0x08, (byte) 0x20, (byte) 0x06, (byte) 0x38, (byte) 0x07, (byte) 0xc4, (byte) 0x05, (byte) 0x08, (byte) 0x20, (byte) 0x06, (byte) 0x46, (byte) 0x26, (byte) 0x26, + (byte) 0x26, (byte) 0xb0, (byte) 0x3e, (byte) 0x10, (byte) 0x00, (byte) 0x08, (byte) 0x20, (byte) 0x54, (byte) 0x53, (byte) 0x00, (byte) 0x02, (byte) 0x08, (byte) 0xc2, (byte) 0x03, (byte) 0x89, (byte) 0x83, (byte) 0x18, (byte) 0x00, (byte) 0x01, (byte) 0x04, (byte) 0xb1, (byte) 0x0f, (byte) 0x06, (byte) 0x00, (byte) 0x02, (byte) 0x08, (byte) 0x22, (byte) 0x07, (byte) 0x02, (byte) 0x20, (byte) 0x06, (byte) 0x40, (byte) 0x00, (byte) 0xa1, (byte) 0xea, (byte) 0x03, (byte) 0x08, (byte) 0x20, + (byte) 0x54, (byte) 0x7d, (byte) 0x00, (byte) 0x01, (byte) 0x06, (byte) 0x00, (byte) 0x78, (byte) 0xe7, (byte) 0x01, (byte) 0x5d, (byte) 0x6f, (byte) 0x06, (byte) 0x04, (byte) 0xbf, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x49, (byte) 0x45, (byte) 0x4e, (byte) 0x44, (byte) 0xae, (byte) 0x42, (byte) 0x60, (byte) 0x82 + }; + + /** mode.png */ + private byte[] mode = { + (byte) 0x89, (byte) 0x50, (byte) 0x4e, (byte) 0x47, (byte) 0x0d, (byte) 0x0a, (byte) 0x1a, (byte) 0x0a, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0d, (byte) 0x49, (byte) 0x48, (byte) 0x44, (byte) 0x52, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0d, (byte) 0x08, (byte) 0x06, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x05, (byte) 0xec, (byte) 0xd4, (byte) 0xea, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x04, (byte) 0x67, + (byte) 0x41, (byte) 0x4d, (byte) 0x41, (byte) 0x00, (byte) 0x00, (byte) 0xaf, (byte) 0xc8, (byte) 0x37, (byte) 0x05, (byte) 0x8a, (byte) 0xe9, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x19, (byte) 0x74, (byte) 0x45, (byte) 0x58, (byte) 0x74, (byte) 0x53, (byte) 0x6f, (byte) 0x66, (byte) 0x74, (byte) 0x77, (byte) 0x61, (byte) 0x72, (byte) 0x65, (byte) 0x00, (byte) 0x41, (byte) 0x64, (byte) 0x6f, (byte) 0x62, (byte) 0x65, (byte) 0x20, (byte) 0x49, (byte) 0x6d, (byte) 0x61, (byte) 0x67, + (byte) 0x65, (byte) 0x52, (byte) 0x65, (byte) 0x61, (byte) 0x64, (byte) 0x79, (byte) 0x71, (byte) 0xc9, (byte) 0x65, (byte) 0x3c, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x3a, (byte) 0x49, (byte) 0x44, (byte) 0x41, (byte) 0x54, (byte) 0x78, (byte) 0xda, (byte) 0x62, (byte) 0x60, (byte) 0x80, (byte) 0x00, (byte) 0x11, (byte) 0x80, (byte) 0x00, (byte) 0x82, (byte) 0xd2, (byte) 0x0c, (byte) 0x8b, (byte) 0x01, (byte) 0x02, (byte) 0x08, (byte) 0xc6, (byte) 0x60, (byte) 0x00, (byte) 0x08, + (byte) 0x20, (byte) 0x10, (byte) 0xba, (byte) 0x0c, (byte) 0x22, (byte) 0x00, (byte) 0x02, (byte) 0x08, (byte) 0x03, (byte) 0x01, (byte) 0x04, (byte) 0x10, (byte) 0x32, (byte) 0x3a, (byte) 0x09, (byte) 0x22, (byte) 0x00, (byte) 0x02, (byte) 0x08, (byte) 0x84, (byte) 0xe2, (byte) 0x81, (byte) 0xb8, (byte) 0x17, (byte) 0xc4, (byte) 0x00, (byte) 0x08, (byte) 0x20, (byte) 0x26, (byte) 0x20, (byte) 0x8e, (byte) 0x05, (byte) 0xe2, (byte) 0x8f, (byte) 0x20, (byte) 0x0e, (byte) 0x40, (byte) 0x00, + (byte) 0xa1, (byte) 0x20, (byte) 0x80, (byte) 0x00, (byte) 0x62, (byte) 0x06, (byte) 0xe2, (byte) 0x7d, (byte) 0x40, (byte) 0xdc, (byte) 0x0a, (byte) 0xc4, (byte) 0xff, (byte) 0x00, (byte) 0x02, (byte) 0x08, (byte) 0x26, (byte) 0xb8, (byte) 0x07, (byte) 0x88, (byte) 0xd5, (byte) 0xa1, (byte) 0xec, (byte) 0x7b, (byte) 0x30, (byte) 0x41, (byte) 0x80, (byte) 0x00, (byte) 0xc2, (byte) 0x8b, (byte) 0x00, (byte) 0x02, (byte) 0x88, (byte) 0x19, (byte) 0x89, (byte) 0x1d, (byte) 0x03, (byte) 0xc4, + (byte) 0x2f, (byte) 0x81, (byte) 0x78, (byte) 0x06, (byte) 0x10, (byte) 0x73, (byte) 0x03, (byte) 0xf1, (byte) 0x25, (byte) 0x80, (byte) 0x00, (byte) 0x42, (byte) 0xf6, (byte) 0x0c, (byte) 0xc8, (byte) 0xd8, (byte) 0x3a, (byte) 0x98, (byte) 0x4a, (byte) 0x80, (byte) 0x00, (byte) 0x02, (byte) 0x21, (byte) 0x5f, (byte) 0x28, (byte) 0xdd, (byte) 0x8b, (byte) 0x2c, (byte) 0x08, (byte) 0x10, (byte) 0x40, (byte) 0xcc, (byte) 0x50, (byte) 0x95, (byte) 0xb7, (byte) 0x80, (byte) 0xf8, (byte) 0x0b, + (byte) 0x10, (byte) 0x73, (byte) 0x01, (byte) 0xf1, (byte) 0x5b, (byte) 0x90, (byte) 0x04, (byte) 0x40, (byte) 0x00, (byte) 0xe1, (byte) 0x44, (byte) 0x00, (byte) 0x01, (byte) 0x84, (byte) 0x8c, (byte) 0x5c, (byte) 0x91, (byte) 0x1c, (byte) 0x72, (byte) 0x19, (byte) 0x20, (byte) 0x80, (byte) 0x98, (byte) 0xa0, (byte) 0x9c, (byte) 0x16, (byte) 0x20, (byte) 0x9e, (byte) 0x0e, (byte) 0x65, (byte) 0x5b, (byte) 0x00, (byte) 0xf1, (byte) 0x41, (byte) 0x80, (byte) 0x00, (byte) 0x62, (byte) 0x46, + (byte) 0xb2, (byte) 0xeb, (byte) 0x01, (byte) 0x10, (byte) 0xf3, (byte) 0x02, (byte) 0xb1, (byte) 0x39, (byte) 0x10, (byte) 0x2b, (byte) 0x03, (byte) 0x04, (byte) 0x10, (byte) 0xcc, (byte) 0x55, (byte) 0xcb, (byte) 0xa0, (byte) 0x21, (byte) 0x01, (byte) 0x73, (byte) 0x36, (byte) 0x8c, (byte) 0x6d, (byte) 0x05, (byte) 0xc4, (byte) 0x47, (byte) 0xd1, (byte) 0xed, (byte) 0x04, (byte) 0x08, (byte) 0x20, (byte) 0x64, (byte) 0xef, (byte) 0xec, (byte) 0xc1, (byte) 0x22, (byte) 0x0e, (byte) 0xf2, + (byte) 0x5e, (byte) 0x01, (byte) 0xba, (byte) 0x20, (byte) 0x40, (byte) 0x00, (byte) 0xc1, (byte) 0xbc, (byte) 0x19, (byte) 0x0c, (byte) 0xc4, (byte) 0x5a, (byte) 0x40, (byte) 0xfc, (byte) 0x03, (byte) 0x1a, (byte) 0x62, (byte) 0x3b, (byte) 0x81, (byte) 0x38, (byte) 0x10, (byte) 0x88, (byte) 0x25, (byte) 0x80, (byte) 0x58, (byte) 0x0d, (byte) 0x88, (byte) 0xef, (byte) 0x00, (byte) 0xf1, (byte) 0x63, (byte) 0x98, (byte) 0x26, (byte) 0x80, (byte) 0x00, (byte) 0x62, (byte) 0xc4, (byte) 0x62, + (byte) 0x3a, (byte) 0xc8, (byte) 0xa7, (byte) 0x4b, (byte) 0xa0, (byte) 0x6c, (byte) 0x71, (byte) 0x20, (byte) 0xae, (byte) 0x85, (byte) 0x6a, (byte) 0x02, (byte) 0x81, (byte) 0xab, (byte) 0x40, (byte) 0xbc, (byte) 0x1b, (byte) 0x20, (byte) 0x80, (byte) 0x98, (byte) 0xb0, (byte) 0x68, (byte) 0x78, (byte) 0x09, (byte) 0x8d, (byte) 0x7a, (byte) 0x06, (byte) 0x28, (byte) 0x9b, (byte) 0x1f, (byte) 0x88, (byte) 0xdf, (byte) 0x00, (byte) 0xf1, (byte) 0x7e, (byte) 0x20, (byte) 0x8e, (byte) 0x03, + (byte) 0x09, (byte) 0x02, (byte) 0x04, (byte) 0x10, (byte) 0xb2, (byte) 0x26, (byte) 0x7d, (byte) 0x68, (byte) 0xca, (byte) 0xdb, (byte) 0x0d, (byte) 0xc4, (byte) 0xc7, (byte) 0xa0, (byte) 0xc1, (byte) 0x89, (byte) 0x0c, (byte) 0x2e, (byte) 0xc2, (byte) 0x0c, (byte) 0x06, (byte) 0x08, (byte) 0x30, (byte) 0x00, (byte) 0x84, (byte) 0x8e, (byte) 0x2c, (byte) 0x30, (byte) 0x86, (byte) 0x31, (byte) 0xc1, (byte) 0x68, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x49, (byte) 0x45, + (byte) 0x4e, (byte) 0x44, (byte) 0xae, (byte) 0x42, (byte) 0x60, (byte) 0x82 + }; + + /** ok.png */ + private byte[] ok = { + (byte) 0x89, (byte) 0x50, (byte) 0x4e, (byte) 0x47, (byte) 0x0d, (byte) 0x0a, (byte) 0x1a, (byte) 0x0a, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0d, (byte) 0x49, (byte) 0x48, (byte) 0x44, (byte) 0x52, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0d, (byte) 0x08, (byte) 0x06, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x05, (byte) 0xec, (byte) 0xd4, (byte) 0xea, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x04, (byte) 0x67, + (byte) 0x41, (byte) 0x4d, (byte) 0x41, (byte) 0x00, (byte) 0x00, (byte) 0xaf, (byte) 0xc8, (byte) 0x37, (byte) 0x05, (byte) 0x8a, (byte) 0xe9, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x19, (byte) 0x74, (byte) 0x45, (byte) 0x58, (byte) 0x74, (byte) 0x53, (byte) 0x6f, (byte) 0x66, (byte) 0x74, (byte) 0x77, (byte) 0x61, (byte) 0x72, (byte) 0x65, (byte) 0x00, (byte) 0x41, (byte) 0x64, (byte) 0x6f, (byte) 0x62, (byte) 0x65, (byte) 0x20, (byte) 0x49, (byte) 0x6d, (byte) 0x61, (byte) 0x67, + (byte) 0x65, (byte) 0x52, (byte) 0x65, (byte) 0x61, (byte) 0x64, (byte) 0x79, (byte) 0x71, (byte) 0xc9, (byte) 0x65, (byte) 0x3c, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x05, (byte) 0x49, (byte) 0x44, (byte) 0x41, (byte) 0x54, (byte) 0x78, (byte) 0xda, (byte) 0x62, (byte) 0xf8, (byte) 0xff, (byte) 0xff, (byte) 0x3f, (byte) 0x03, (byte) 0x13, (byte) 0x13, (byte) 0x13, (byte) 0x03, (byte) 0x40, (byte) 0x00, (byte) 0x31, (byte) 0x31, (byte) 0x40, (byte) 0x01, (byte) 0x40, (byte) 0x00, + (byte) 0x31, (byte) 0x82, (byte) 0x78, (byte) 0x40, (byte) 0xe0, (byte) 0x00, (byte) 0x10, (byte) 0x40, (byte) 0x20, (byte) 0x61, (byte) 0x03, (byte) 0x10, (byte) 0x07, (byte) 0x20, (byte) 0x80, (byte) 0x18, (byte) 0xe0, (byte) 0x6a, (byte) 0x98, (byte) 0x98, (byte) 0xee, (byte) 0x83, (byte) 0x68, (byte) 0x80, (byte) 0x00, (byte) 0x62, (byte) 0x04, (byte) 0x09, (byte) 0x20, (byte) 0x03, (byte) 0x80, (byte) 0x00, (byte) 0x82, (byte) 0xe9, (byte) 0x01, (byte) 0x03, (byte) 0x80, (byte) 0x00, + (byte) 0x62, (byte) 0x42, (byte) 0x96, (byte) 0x01, (byte) 0x08, (byte) 0x20, (byte) 0x66, (byte) 0x46, (byte) 0x46, (byte) 0xc6, (byte) 0x7a, (byte) 0x90, (byte) 0x0a, (byte) 0x20, (byte) 0x7e, (byte) 0x00, (byte) 0x10, (byte) 0x40, (byte) 0x28, (byte) 0xfa, (byte) 0x00, (byte) 0x02, (byte) 0x08, (byte) 0xd9, (byte) 0x54, (byte) 0x64, (byte) 0x7c, (byte) 0x1e, (byte) 0x44, (byte) 0x03, (byte) 0x04, (byte) 0x10, (byte) 0x4c, (byte) 0xd2, (byte) 0x00, (byte) 0x2a, (byte) 0xb8, (byte) 0x1f, + (byte) 0x59, (byte) 0x11, (byte) 0x40, (byte) 0x00, (byte) 0x81, (byte) 0x8d, (byte) 0x61, (byte) 0x66, (byte) 0x66, (byte) 0x06, (byte) 0x1b, (byte) 0x02, (byte) 0x35, (byte) 0x1b, (byte) 0x0e, (byte) 0x00, (byte) 0x02, (byte) 0x08, (byte) 0xc5, (byte) 0x29, (byte) 0xc8, (byte) 0x00, (byte) 0x20, (byte) 0x80, (byte) 0x58, (byte) 0xb0, (byte) 0x88, (byte) 0x19, (byte) 0x80, (byte) 0x08, (byte) 0x80, (byte) 0x00, (byte) 0x62, (byte) 0xc2, (byte) 0x26, (byte) 0x08, (byte) 0x04, (byte) 0x17, + (byte) 0x00, (byte) 0x02, (byte) 0x08, (byte) 0x5d, (byte) 0xc2, (byte) 0x1f, (byte) 0x24, (byte) 0x08, (byte) 0x62, (byte) 0x00, (byte) 0x04, (byte) 0x10, (byte) 0xcc, (byte) 0xa8, (byte) 0xf7, (byte) 0x40, (byte) 0x2c, (byte) 0x80, (byte) 0xec, (byte) 0x00, (byte) 0x80, (byte) 0x00, (byte) 0x82, (byte) 0xe9, (byte) 0x58, (byte) 0x00, (byte) 0xc4, (byte) 0x8e, (byte) 0xc8, (byte) 0x5a, (byte) 0x01, (byte) 0x02, (byte) 0x08, (byte) 0x23, (byte) 0xc4, (byte) 0x60, (byte) 0x00, (byte) 0x20, + (byte) 0x80, (byte) 0x90, (byte) 0xfd, (byte) 0x42, (byte) 0x08, (byte) 0x80, (byte) 0xac, (byte) 0xea, (byte) 0x07, (byte) 0xe2, (byte) 0x8d, (byte) 0x00, (byte) 0x01, (byte) 0x84, (byte) 0x2b, (byte) 0xe8, (byte) 0x90, (byte) 0xb1, (byte) 0x01, (byte) 0x34, (byte) 0xb2, (byte) 0x60, (byte) 0x21, (byte) 0xc8, (byte) 0x00, (byte) 0x10, (byte) 0x40, (byte) 0x4c, (byte) 0x04, (byte) 0x4c, (byte) 0x86, (byte) 0x79, (byte) 0x46, (byte) 0x11, (byte) 0xe6, (byte) 0x4b, (byte) 0x10, (byte) 0x00, + (byte) 0x08, (byte) 0x20, (byte) 0x98, (byte) 0x4d, (byte) 0x0e, (byte) 0x40, (byte) 0xfc, (byte) 0x1f, (byte) 0x88, (byte) 0x0b, (byte) 0xa0, (byte) 0xa6, (byte) 0xd5, (byte) 0xc3, (byte) 0x22, (byte) 0x0a, (byte) 0x1b, (byte) 0x06, (byte) 0x08, (byte) 0x20, (byte) 0x64, (byte) 0xe7, (byte) 0x09, (byte) 0x00, (byte) 0xf1, (byte) 0x7b, (byte) 0x28, (byte) 0x5e, (byte) 0x8f, (byte) 0xcf, (byte) 0xc9, (byte) 0x00, (byte) 0x01, (byte) 0x84, (byte) 0x1e, (byte) 0x10, (byte) 0x06, (byte) 0x50, + (byte) 0xe7, (byte) 0x1c, (byte) 0xc0, (byte) 0x17, (byte) 0x22, (byte) 0x00, (byte) 0x01, (byte) 0x06, (byte) 0x00, (byte) 0x3b, (byte) 0x85, (byte) 0x3d, (byte) 0x34, (byte) 0xf3, (byte) 0xcf, (byte) 0x64, (byte) 0xe7, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x49, (byte) 0x45, (byte) 0x4e, (byte) 0x44, (byte) 0xae, (byte) 0x42, (byte) 0x60, (byte) 0x82 + }; + + /** shift.png */ + private byte[] shift = { + (byte) 0x89, (byte) 0x50, (byte) 0x4e, (byte) 0x47, (byte) 0x0d, (byte) 0x0a, (byte) 0x1a, (byte) 0x0a, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0d, (byte) 0x49, (byte) 0x48, (byte) 0x44, (byte) 0x52, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0d, (byte) 0x08, (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x45, (byte) 0x35, (byte) 0x14, (byte) 0x4e, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x04, (byte) 0x67, + (byte) 0x41, (byte) 0x4d, (byte) 0x41, (byte) 0x00, (byte) 0x00, (byte) 0xb1, (byte) 0x8e, (byte) 0x7c, (byte) 0xfb, (byte) 0x51, (byte) 0x93, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x20, (byte) 0x63, (byte) 0x48, (byte) 0x52, (byte) 0x4d, (byte) 0x00, (byte) 0x00, (byte) 0x7a, (byte) 0x25, (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x83, (byte) 0x00, (byte) 0x00, (byte) 0xf9, (byte) 0xff, (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0xe6, (byte) 0x00, (byte) 0x00, (byte) 0x75, + (byte) 0x2e, (byte) 0x00, (byte) 0x00, (byte) 0xea, (byte) 0x5f, (byte) 0x00, (byte) 0x00, (byte) 0x3a, (byte) 0x97, (byte) 0x00, (byte) 0x00, (byte) 0x17, (byte) 0x6f, (byte) 0x69, (byte) 0xe4, (byte) 0xc4, (byte) 0x2b, (byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0x00, (byte) 0x50, (byte) 0x4c, (byte) 0x54, (byte) 0x45, (byte) 0xe6, (byte) 0xe6, (byte) 0xe6, (byte) 0xcc, (byte) 0xcc, (byte) 0xcc, (byte) 0x7d, (byte) 0x7d, (byte) 0x7d, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xa0, (byte) 0xe5, (byte) 0xcc, (byte) 0x14, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x04, (byte) 0x74, (byte) 0x52, (byte) 0x4e, (byte) 0x53, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00, (byte) 0x40, (byte) 0x2a, (byte) 0xa9, (byte) 0xf4, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x60, (byte) 0x49, (byte) 0x44, (byte) 0x41, (byte) 0x54, (byte) 0x78, (byte) 0x9c, (byte) 0x62, (byte) 0x60, (byte) 0x06, (byte) 0x03, (byte) 0x46, (byte) 0x08, (byte) 0x05, (byte) 0x10, (byte) 0x40, (byte) 0x0c, (byte) 0x10, (byte) 0x0e, (byte) 0x03, + (byte) 0x13, (byte) 0x98, (byte) 0x06, (byte) 0x08, (byte) 0x20, (byte) 0x06, (byte) 0x08, (byte) 0x87, (byte) 0x01, (byte) 0xc2, (byte) 0x05, (byte) 0x08, (byte) 0x20, (byte) 0x06, (byte) 0x28, (byte) 0x07, (byte) 0xc2, (byte) 0x05, (byte) 0x08, (byte) 0x20, (byte) 0x06, (byte) 0x18, (byte) 0x07, (byte) 0xcc, (byte) 0x05, (byte) 0x08, (byte) 0x20, (byte) 0x06, (byte) 0x38, (byte) 0x07, (byte) 0xc4, (byte) 0x05, (byte) 0x08, (byte) 0x20, (byte) 0x06, (byte) 0x46, (byte) 0x26, (byte) 0x26, + (byte) 0x26, (byte) 0xb0, (byte) 0x3e, (byte) 0x10, (byte) 0x00, (byte) 0x08, (byte) 0x20, (byte) 0x54, (byte) 0x53, (byte) 0x00, (byte) 0x02, (byte) 0x08, (byte) 0x95, (byte) 0x07, (byte) 0x10, (byte) 0x40, (byte) 0xa8, (byte) 0x3c, (byte) 0x80, (byte) 0x00, (byte) 0x42, (byte) 0xe5, (byte) 0x01, (byte) 0x04, (byte) 0x10, (byte) 0x2a, (byte) 0x0f, (byte) 0x20, (byte) 0x80, (byte) 0x20, (byte) 0x3c, (byte) 0x90, (byte) 0x79, (byte) 0x20, (byte) 0x06, (byte) 0x40, (byte) 0x80, (byte) 0x01, + (byte) 0x00, (byte) 0x74, (byte) 0xd7, (byte) 0x01, (byte) 0x49, (byte) 0x4a, (byte) 0xc4, (byte) 0x00, (byte) 0x8f, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x49, (byte) 0x45, (byte) 0x4e, (byte) 0x44, (byte) 0xae, (byte) 0x42, (byte) 0x60, (byte) 0x82 + }; + + private byte[] cn = { + (byte) 0x89, (byte) 0x50, (byte) 0x4e, (byte) 0x47, (byte) 0x0d, (byte) 0x0a, (byte) 0x1a, (byte) 0x0a, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0d, (byte) 0x49, (byte) 0x48, (byte) 0x44, (byte) 0x52, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0d, (byte) 0x08, (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xfd, (byte) 0x89, (byte) 0x73, (byte) 0x2b, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x73, + (byte) 0x52, (byte) 0x47, (byte) 0x42, (byte) 0x00, (byte) 0xae, (byte) 0xce, (byte) 0x1c, (byte) 0xe9, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x04, (byte) 0x67, (byte) 0x41, (byte) 0x4d, (byte) 0x41, (byte) 0x00, (byte) 0x00, (byte) 0xb1, (byte) 0x8f, (byte) 0x0b, (byte) 0xfc, (byte) 0x61, (byte) 0x05, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x20, (byte) 0x63, (byte) 0x48, (byte) 0x52, (byte) 0x4d, (byte) 0x00, (byte) 0x00, (byte) 0x7a, (byte) 0x26, (byte) 0x00, (byte) 0x00, + (byte) 0x80, (byte) 0x84, (byte) 0x00, (byte) 0x00, (byte) 0xfa, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0xe8, (byte) 0x00, (byte) 0x00, (byte) 0x75, (byte) 0x30, (byte) 0x00, (byte) 0x00, (byte) 0xea, (byte) 0x60, (byte) 0x00, (byte) 0x00, (byte) 0x3a, (byte) 0x98, (byte) 0x00, (byte) 0x00, (byte) 0x17, (byte) 0x70, (byte) 0x9c, (byte) 0xba, (byte) 0x51, (byte) 0x3c, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x33, (byte) 0x49, (byte) 0x44, (byte) 0x41, (byte) 0x54, + (byte) 0x28, (byte) 0x53, (byte) 0x63, (byte) 0xfc, (byte) 0xff, (byte) 0xff, (byte) 0x3f, (byte) 0x03, (byte) 0x31, (byte) 0x00, (byte) 0xa8, (byte) 0x0e, (byte) 0x0d, (byte) 0x00, (byte) 0x75, (byte) 0x61, (byte) 0x11, (byte) 0x24, (byte) 0x4d, (byte) 0x1d, (byte) 0x1e, (byte) 0x9b, (byte) 0x21, (byte) 0x06, (byte) 0x41, (byte) 0xad, (byte) 0x40, (byte) 0xb6, (byte) 0x0b, (byte) 0x2b, (byte) 0x7b, (byte) 0xe0, (byte) 0xd5, (byte) 0xe1, (byte) 0xf2, (byte) 0x0a, (byte) 0x8a, (byte) 0x3f, + (byte) 0x90, (byte) 0x43, (byte) 0x87, (byte) 0x1a, (byte) 0xe1, (byte) 0x47, (byte) 0x35, (byte) 0xf3, (byte) 0x00, (byte) 0x1d, (byte) 0x23, (byte) 0x69, (byte) 0xa6, (byte) 0xf7, (byte) 0x74, (byte) 0x7d, (byte) 0x20, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x49, (byte) 0x45, (byte) 0x4e, (byte) 0x44, (byte) 0xae, (byte) 0x42, (byte) 0x60, (byte) 0x82 + }; +} + +/* */