/* * $Id$ * * Copyright (C) 2003-2015 JNode.org * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library 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 Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; If not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.jnode.driver.textscreen.swing; import java.awt.AWTEvent; import java.awt.AWTKeyStroke; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.KeyboardFocusManager; import java.awt.Toolkit; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionListener; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import java.util.ArrayList; import java.util.HashSet; import java.util.Set; import javax.swing.JComponent; import javax.swing.KeyStroke; import javax.swing.SwingUtilities; import org.jnode.driver.Bus; import org.jnode.driver.Device; import org.jnode.driver.Driver; import org.jnode.driver.DriverException; import org.jnode.driver.input.KeyboardAPI; import org.jnode.driver.input.KeyboardEvent; import org.jnode.driver.input.KeyboardInterpreter; import org.jnode.driver.input.KeyboardListener; import org.jnode.driver.input.PointerAPI; import org.jnode.driver.input.PointerEvent; import org.jnode.driver.input.PointerListener; import org.jnode.driver.textscreen.TextScreen; import org.jnode.driver.textscreen.x86.AbstractPcTextScreen; /** * A Swing based emulator for PcTextScreen. * * @author Levente S\u00e1ntha */ public class SwingPcTextScreen extends AbstractPcTextScreen { private static final int SCREEN_WIDTH = 80; private static final int SCREEN_HEIGHT = 25; char[] buffer; private int cursorOffset; private JComponent screen; private MyKeyboardDriver keyboardDriver = null; private Device keyboardDevice; private KeyAdapter keyListener; private MyPointerDriver pointerDriver = null; private Device pointerDevice; private MouseHandler mouseListener; public SwingPcTextScreen() { super(SCREEN_WIDTH, SCREEN_HEIGHT); buffer = new char[SCREEN_WIDTH * SCREEN_HEIGHT]; for (int i = 0; i < buffer.length; i++) { buffer[i] = ' '; } screen = new SwingPcScreen(); } public void close() { screen.removeKeyListener(keyListener); screen.removeMouseListener(mouseListener); screen.removeMouseMotionListener(mouseListener); screen.removeMouseWheelListener(mouseListener); } public JComponent getScreenComponent() { return screen; } private class SwingPcScreen extends JComponent { private static final long serialVersionUID = 1L; int margin = 5; int w; int h; { Dimension screen_size = Toolkit.getDefaultToolkit().getScreenSize(); Font font = screen_size.width > 800 ? new Font("-dosemu-VGA-Medium-R-Normal--19-190-75-75-C-100-IBM-", Font.PLAIN, 18) : new Font("-Misc-Fixed-Medium-R-SemiCondensed--12-110-75-75-C-60-437-", Font.PLAIN, 12); // Font font = new Font("-Misc-Fixed-Medium-R-SemiCondensed--12-110-75-75-C-60-437-", Font.PLAIN, 12); //Font font = new Font( //"-FontForge-Bitstream Vera Sans Mono-Book-R-Normal-SansMono--12-120-75-75-P-69-ISO10646", Font.PLAIN, 12); //Font font = new Font("-FontForge-Bitstream Vera Sans // Mono-Book-R-Normal-SansMono--12-120-75-75-P-69-FontSpecific", Font.PLAIN, 12); //Font font = new Font("-FontForge-Bitstream Vera Sans // Mono-Book-R-Normal-SansMono--14-100-100-100-P-79-FontSpecific", Font.PLAIN, 12); // Font font = Font.decode("MONOSPACED-PLAIN-14"); setFont(font); enableEvents(AWTEvent.KEY_EVENT_MASK); enableEvents(AWTEvent.FOCUS_EVENT_MASK); addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { if (SwingUtilities.isLeftMouseButton(e)) { if (contains(e.getX(), e.getY())) { if (!hasFocus() && isRequestFocusEnabled()) { requestFocus(); } } } } }); setFocusable(true); setBackground(Color.BLACK); Set<AWTKeyStroke> ftk = new HashSet<AWTKeyStroke>( getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS)); ftk.remove(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0)); setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, ftk); } @Override protected void paintComponent(Graphics g) { g.setColor(getBackground()); g.fillRect(0, 0, getWidth(), getHeight()); g.setColor(Color.WHITE); for (int i = 0; i < SCREEN_HEIGHT; i++) { int offset = i * SCREEN_WIDTH; int lenght = SCREEN_WIDTH; if (offset <= cursorOffset && cursorOffset < offset + SCREEN_WIDTH) { FontMetrics fm = getFontMetrics(getFont()); int x = margin + fm.charsWidth(buffer, offset, cursorOffset - offset); int y = h + i * h; int width = fm.charWidth(buffer[cursorOffset]); g.drawLine(x, y, x + width, y); } g.drawChars(buffer, offset, lenght, margin, h + i * h); } } @Override public void addNotify() { super.addNotify(); FontMetrics fm = getGraphics().getFontMetrics(); w = fm.getMaxAdvance(); h = fm.getHeight(); screen.setSize(screen.getMaximumSize()); } @Override public Dimension getPreferredSize() { return new Dimension(w * SCREEN_WIDTH + 2 * margin, (h + 1) * SCREEN_HEIGHT + 2 * margin); } @Override public Dimension getMaximumSize() { return getPreferredSize(); } } public Device getKeyboardDevice() { if (keyboardDevice == null) { keyboardDriver = new MyKeyboardDriver(); keyListener = new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { KeyboardEvent k = new KeyboardEvent(KeyEvent.KEY_PRESSED, e.getWhen(), e.getModifiersEx(), e.getKeyCode(), e.getKeyChar()); keyboardDriver.dispatchEvent(k); } @Override public void keyReleased(KeyEvent e) { KeyboardEvent k = new KeyboardEvent(KeyEvent.KEY_RELEASED, e.getWhen(), e.getModifiersEx(), e.getKeyCode(), e.getKeyChar()); keyboardDriver.dispatchEvent(k); } }; screen.addKeyListener(keyListener); keyboardDevice = new Device(new Bus((Bus) null) { }, ""); try { keyboardDevice.setDriver(keyboardDriver); keyboardDriver.startDevice(); } catch (DriverException x) { throw new RuntimeException(x); } } return keyboardDevice; } private class MouseHandler extends MouseAdapter implements MouseMotionListener, MouseWheelListener { @Override public void mousePressed(MouseEvent e) { // todo complete event parameters PointerEvent p = new PointerEvent(0, e.getX(), e.getY(), true); pointerDriver.dispatchEvent(p); } @Override public void mouseReleased(MouseEvent e) { // todo complete event parameters PointerEvent p = new PointerEvent(0, e.getX(), e.getY(), true); pointerDriver.dispatchEvent(p); } @Override public void mouseDragged(MouseEvent e) { // todo complete event parameters PointerEvent p = new PointerEvent(0, e.getX(), e.getY(), true); pointerDriver.dispatchEvent(p); } @Override public void mouseMoved(MouseEvent e) { // todo complete event parameters PointerEvent p = new PointerEvent(0, e.getX(), e.getY(), true); pointerDriver.dispatchEvent(p); } @Override public void mouseWheelMoved(MouseWheelEvent e) { // todo complete event parameters PointerEvent p = new PointerEvent(0, e.getX(), e.getY(), e.getWheelRotation(), true); pointerDriver.dispatchEvent(p); } } public Device getPointerDevice() { if (pointerDevice == null) { pointerDriver = new MyPointerDriver(); mouseListener = new MouseHandler(); screen.addMouseListener(mouseListener); screen.addMouseMotionListener(mouseListener); screen.addMouseWheelListener(mouseListener); pointerDevice = new Device(new Bus((Bus) null) { }, ""); try { pointerDevice.setDriver(pointerDriver); pointerDriver.startDevice(); } catch (DriverException x) { throw new RuntimeException(x); } } return pointerDevice; } public char getChar(int offset) { return buffer[offset]; } public int getColor(int offset) { return 0; } public void set(int offset, char ch, int count, int color) { char c = (char) (ch & 0xFF); c = ((c == 0) ? ' ' : c); for (int i = 0; i < count; i++) { buffer[offset] = c; } sync(offset, count); } public void set(int offset, char[] ch, int chOfs, int length, int color) { char[] cha = new char[ch.length]; for (int i = 0; i < cha.length; i++) { char c = (char) (ch[i] & 0xFF); cha[i] = c == 0 ? ' ' : c; } System.arraycopy(cha, chOfs, buffer, offset, length); sync(offset, length); } public void set(int offset, char[] ch, int chOfs, int length, int[] colors, int colorsOfs) { char[] cha = new char[ch.length]; for (int i = 0; i < cha.length; i++) { char c = (char) (ch[i] & 0xFF); cha[i] = c == 0 ? ' ' : c; } System.arraycopy(cha, chOfs, buffer, offset, length); sync(offset, length); } public void copyContent(int srcOffset, int destOffset, int length) { System.arraycopy(buffer, srcOffset * 2, buffer, destOffset * 2, length * 2); sync(destOffset * 2, length * 2); } public void copyTo(TextScreen dst, int offset, int length) { } Runnable repaintCmd = new Runnable() { public void run() { screen.repaint(); } }; @Override public void sync(int offset, int length) { SwingUtilities.invokeLater(repaintCmd); } public int setCursor(int x, int y) { cursorOffset = getOffset(x, y); return cursorOffset; } public int setCursorVisible(boolean visible) { return cursorOffset; } /** * Copy the content of the given rawData into this screen. * * @param rawData * @param rawDataOffset */ public void copyFrom(char[] rawData, int rawDataOffset) { if (rawDataOffset < 0) { // Unsafe.die("Screen:rawDataOffset = " + rawDataOffset); } char[] cha = new char[rawData.length]; for (int i = 0; i < cha.length; i++) { char c = (char) (rawData[i] & 0xFF); cha[i] = c == 0 ? ' ' : c; } System.arraycopy(cha, rawDataOffset, buffer, 0, getWidth() * getHeight()); sync(0, getWidth() * getHeight()); } private static class MyPointerDriver extends Driver implements PointerAPI { private final ArrayList<PointerListener> listeners = new ArrayList<PointerListener>(); @Override protected synchronized void startDevice() throws DriverException { getDevice().registerAPI(PointerAPI.class, this); } @Override protected synchronized void stopDevice() throws DriverException { } void dispatchEvent(PointerEvent event) { for (PointerListener l : listeners) { l.pointerStateChanged(event); if (event.isConsumed()) { break; } } } @Override public void addPointerListener(PointerListener l) { listeners.add(l); } @Override public void removePointerListener(PointerListener l) { listeners.remove(l); } /** * Claim to be the preferred listener. * The given listener must have been added by addPointerListener. * If there is a security manager, this method will call * <code>checkPermission(new DriverPermission("setPreferredListener"))</code>. * * @param listener the prefered pointer listener */ @Override public void setPreferredListener(PointerListener listener) { } } private static class MyKeyboardDriver extends Driver implements KeyboardAPI { private final ArrayList<KeyboardListener> listeners = new ArrayList<KeyboardListener>(); @Override protected synchronized void startDevice() throws DriverException { getDevice().registerAPI(KeyboardAPI.class, this); } @Override protected synchronized void stopDevice() throws DriverException { } void dispatchEvent(KeyboardEvent event) { for (KeyboardListener l : listeners) { sendEvent(l, event); if (event.isConsumed()) { break; } } } protected void sendEvent(KeyboardListener l, KeyboardEvent event) { if (event.isKeyPressed()) { l.keyPressed(event); } else if (event.isKeyReleased()) { l.keyReleased(event); } } @Override public void addKeyboardListener(KeyboardListener l) { listeners.add(l); } @Override public KeyboardInterpreter getKbInterpreter() { return null; } @Override public void removeKeyboardListener(KeyboardListener l) { listeners.remove(l); } @Override public void setKbInterpreter(KeyboardInterpreter kbInterpreter) { } @Override public void setPreferredListener(KeyboardListener l) { } } }