// This program must be compiled on a Japanese system. import java.lang.*; import java.awt.*; import java.awt.event.*; import java.awt.image.*; import java.net.*; import java.applet.*; import java.util.*; final public class KanaType extends Applet implements Runnable, KeyListener, ItemListener, AdjustmentListener { boolean _fInit = false, _fError = false; Thread _thread = null; StringBuffer _sb = new StringBuffer(), _sbHiragana = new StringBuffer(); int _cxChars = 0; FontMetrics _fm; Choice _choiceFont; Scrollbar _scrollbar; Hashtable _hashImg; int _iImgSize; int _cxString1, _cxString2, _iCharOffset; int _iScroll = 0; static Hashtable _hashPhon, _hashRoman; static int _cKana = makeHash(); final static String _strWait = "Now loading images..."; final static String _strError = "Image load error!"; final static String _astrFonts[] = { "Gothic", "Kaisho", "MaruGothic", "Mincho", "Pop", "Textbook" }; String _strFont = "Textbook"; boolean _fKata = false; final static String _strKana = "あいうえおかきくけこがぎぐげごさしすせそざじずぜぞたちつてとだぢづでどなにぬねのはひふへほばびぶべぼぱぴぷぺぽまみむめもやゆよらりるれろわゐゑをんっゃゅょぁぃぅぇぉー、。?!"; final static String _strHashPhon = "a あ i い u う e え o お ka か ki き ku く ke け ko こ ga が gi ぎ gu ぐ ge げ go ご sa さ si し su す se せ so そ za ざ zi じ zu ず ze ぜ zo ぞ ta た ti ち tu つ te て to と da だ di ぢ du づ de で do ど na な ni に nu ぬ ne ね no の ha は hi ひ hu ふ he へ ho ほ ba ば bi び bu ぶ be べ bo ぼ pa ぱ pi ぴ pu ぷ pe ぺ po ぽ ma ま mi み mu む me め mo も ya や yu ゆ yo よ ra ら ri り ru る re れ ro ろ wa わ wi ゐ we ゑ wo を N ん Q っ kya きゃ kyu きゅ kyo きょ gya ぎゃ gyu ぎゅ gyo ぎょ sya しゃ syu しゅ syo しょ zya じゃ zyu じゅ zyo じょ tya ちゃ tyu ちゅ tyo ちょ dya ぢゃ dyu ぢゅ dyo ぢょ nya にゃ nyu にゅ nyo にょ hya ひゃ hyu ひゅ hyo ひょ bya びゃ byu びゅ byo びょ pya ぴゃ pyu ぴゅ pyo ぴょ mya みゃ myu みゅ myo みょ rya りゃ ryu りゅ ryo りょ - ー , 、 . 。 ? ? ! !"; final static String _strHashRoman = "sha sya shi si shu syu sho syo ja zya ji zi ju zyu jo zyo cha tya chi ti chu tyu cho tyo tsu tu fu hu"; final private static int makeHash() { _hashPhon = new Hashtable(); _hashRoman = new Hashtable(); int cKana = 0; StringTokenizer st = new StringTokenizer(_strHashPhon, " "); do { _hashPhon.put(st.nextToken(), st.nextToken()); cKana++; } while (st.hasMoreTokens()); st = new StringTokenizer(_strHashRoman, " "); do { _hashRoman.put(st.nextToken(), st.nextToken()); } while (st.hasMoreTokens()); return cKana; } final public void init() { Color color = new Color(0xf0, 0xf0, 0xf7); setBackground(color); Choice choice = new Choice(); for (int iIndex = 0; iIndex < _astrFonts.length; iIndex++) { choice.addItem(_astrFonts[iIndex] + ", Hiragana"); choice.addItem(_astrFonts[iIndex] + ", Katakana"); } choice.select(_strFont + ", Hiragana"); choice.addItemListener(this); add(_choiceFont = choice); add(_scrollbar = new Scrollbar(Scrollbar.HORIZONTAL, 0, 1, 0, 0)); _scrollbar.addAdjustmentListener(this); Font fontOld = getFont(), fontNew = new Font("serif", Font.BOLD, 32); setFont(fontNew); choice.setFont(fontOld); FontMetrics fm = _fm = getFontMetrics(fontNew); _cxString1 = fm.stringWidth(_strWait); _cxString2 = fm.stringWidth(_strError); _iCharOffset = fm.getMaxAscent() - fm.getMaxDescent(); if (!_fInit && !_fError && _thread == null) { (_thread = new Thread(this)).start(); } addKeyListener(this); } final public void start() { requestFocus(); } final private void setScrollbar() { int iScrollbarWidth = _scrollbar.getSize().width; int iVisible = Math.min(_cxChars, iScrollbarWidth); int iOffset = Math.min(_cxChars - iVisible, _iScroll); _scrollbar.setValues(iOffset, iScrollbarWidth, 0, _cxChars); _scrollbar.setBlockIncrement(iVisible); _iScroll = iOffset; } final public synchronized void doLayout() { if (_choiceFont != null) { Dimension dim = getSize(); int iWidth = dim.width, iHeight = dim.height; dim = _choiceFont.getPreferredSize(); _choiceFont.setBounds(0, 0, Math.min(iWidth / 2, dim.width), Math.min(iHeight / 4, dim.height)); if (_scrollbar != null) { int iScrollbarHeight = _scrollbar.getPreferredSize().height; _scrollbar.setBounds(0, iHeight - iScrollbarHeight, iWidth, iScrollbarHeight); setScrollbar(); } } } final public void run() { try { Image image = getImage(getCodeBase(), _strFont.toLowerCase() + (_fKata ? "_k.gif" : ".gif")); MediaTracker media = new MediaTracker(this); media.addImage(image, 0); media.waitForAll(); if (media.isErrorAny()) { _fError = true; } else { int cImages = _strKana.length(), iImgSize = _iImgSize = image.getHeight(this); ImageProducer imgprod = image.getSource(); _hashImg = new Hashtable(); for (int iIndex = 0; iIndex < cImages; iIndex++) { _hashImg.put(new Character(_strKana.charAt(iIndex)), createImage(new FilteredImageSource (imgprod, new CropImageFilter(iIndex * iImgSize, 0, iImgSize, iImgSize)))); } _scrollbar.setUnitIncrement(iImgSize); _fInit = true; } } catch (Exception e) { _fError = true; } _thread = null; repaint(); } final public void paint(Graphics g) { Dimension dim = getSize(); int yOffset = dim.height * 3 / 8; int cx = dim.width, cy = dim.height - yOffset - _scrollbar.getSize().height; int yString = (cy + _iCharOffset) / 2 + yOffset; if (_fError) { g.drawString(_strError, (cx - _cxString2) / 2, yString); } else if (_fInit) { int x = -_iScroll, yImage = (cy - _iImgSize) / 2 + yOffset; int iLength = _sbHiragana.length(); for (int iIndex = 0; iIndex < iLength; iIndex++) { char c = _sbHiragana.charAt(iIndex); if (c != ' ') { g.drawImage((Image)_hashImg.get(new Character(c)), x, yImage, this); } x += _iImgSize; } g.drawString(_sb.toString(), x + 10, yString); } else { g.drawString(_strWait, (cx - _cxString1) / 2, yString); } } final private void charChanged(int cHiragana) { int iScrollPrev = _iScroll; _cxChars = _sbHiragana.length() * _iImgSize + 10 + _fm.stringWidth(_sb.toString()); setScrollbar(); Dimension dim = getSize(); if (iScrollPrev == _iScroll) { repaint(cHiragana * _iImgSize - iScrollPrev, 0, dim.width, dim.height); } else { repaint(); } } final public void keyPressed(KeyEvent ke) { if (_fInit) { if (ke.getKeyCode() == KeyEvent.VK_BACK_SPACE) { int cChars = _sb.length(), cHiragana = _sbHiragana.length(); if (cChars > 0) { _sb.setLength(cChars - 1); charChanged(cHiragana); } else if (cHiragana > 0) { _sbHiragana.setLength(--cHiragana); charChanged(cHiragana); } } } } final public void keyReleased(KeyEvent ke) { } final public void keyTyped(KeyEvent ke) { char cKey; if (_fInit && (cKey = ke.getKeyChar()) >= 0x20 && cKey <= 0x7e) { int cHiragana = _sbHiragana.length(), cChars; String strAlphabet, strKana; if (_hashRoman.containsKey(strAlphabet = _sb.append(cKey).toString())) { strAlphabet = (String)_hashRoman.get(strAlphabet); } if (strAlphabet.equals(" ")) { _sbHiragana.append(' '); _sb.setLength(0); } else if ((strKana = (String)_hashPhon.get(strAlphabet)) != null) { _sbHiragana.append(strKana); _sb.setLength(0); } else if ((cChars = strAlphabet.length()) >= 2) { char c0 = strAlphabet.charAt(0), c1 = strAlphabet.charAt(1); if (cChars == 2 && ((c0 == 'n' && c1 != 'y') || (c0 == 'm' && (c1 == 'm' || c1 == 'b' || c1 == 'p')))) { _sbHiragana.append('ん'); _sb.setLength(0); if (!(c0 == 'n' && (c1 == '\'' || c1 == '-'))) { _sb.append(c1); } } else if (c0 == c1 || strAlphabet.equals("tch")) { _sbHiragana.append('っ'); _sb = new StringBuffer(strAlphabet.substring(1)); } } charChanged(cHiragana); } } final public void adjustmentValueChanged(AdjustmentEvent ae) { _iScroll = _scrollbar.getValue(); repaint(); } final public void itemStateChanged(ItemEvent ie) { Object obj = ie.getItem(); if (obj instanceof String) { String str = (String)obj; int iIndex = str.indexOf(','); String strFont = str.substring(0, iIndex); boolean fKata = (str.charAt(iIndex + 2) == 'K'); if (fKata != _fKata || !strFont.equals(_strFont)) { _strFont = strFont; _fKata = fKata; if (_thread != null) { _thread.stop(); } _fInit = _fError = false; (_thread = new Thread(this)).start(); repaint(); } } } }