Dépôt officiel du code source de l'ERP OpenConcerto
Rev 156 | Rev 182 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.erp.core.sales.pos.io;
import org.openconcerto.erp.core.sales.pos.ui.BarcodeListener;
import org.openconcerto.ui.DefaultGridBagConstraints;
import org.openconcerto.ui.component.ITextArea;
import org.openconcerto.utils.StringUtils;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.KeyEventDispatcher;
import java.awt.KeyboardFocusManager;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
/**
* Lecteur code barres, intercepte les événements clavier pour détecter un scan de code. Le code
* barre doit terminer par un retour à la ligne.
*/
public class BarcodeReader implements KeyEventDispatcher {
public int maxInterKeyDelay = 80;
private static final int MIN_BARCODE_LENGTH = 2;
private final List<BarcodeListener> listeners = new ArrayList<BarcodeListener>(1);
private String value = "";
private final List<KeyEvent> eve = new ArrayList<KeyEvent>();
private long firstTime = -1;
private Timer timer;
// non final car un TimerTask n'est pas reutilisable
private TimerTask task;
private boolean enable = true;
private boolean debug = false;
Map<Integer, String> mapCharacterFR = new HashMap<>();
public BarcodeReader(int maxInterKeyDelay) {
this.timer = null;
this.task = null;
this.maxInterKeyDelay = maxInterKeyDelay;
this.mapCharacterFR.put((int) '&', "1");
this.mapCharacterFR.put((int) 'é', "2");
this.mapCharacterFR.put((int) '"', "3");
this.mapCharacterFR.put((int) '\'', "4");
this.mapCharacterFR.put((int) '(', "5");
this.mapCharacterFR.put((int) '-', "6");
this.mapCharacterFR.put((int) 'è', "7");
this.mapCharacterFR.put((int) '_', "8");
this.mapCharacterFR.put((int) 'ç', "9");
this.mapCharacterFR.put((int) 'à', "0");
}
public synchronized void removeBarcodeListener(BarcodeListener l) {
this.listeners.remove(l);
if (this.listeners.isEmpty()) {
stop();
}
}
public synchronized void addBarcodeListener(final BarcodeListener l) {
if (this.timer == null) {
start();
}
this.listeners.add(l);
}
private void fire(String code) {
for (int i = 0; i < this.listeners.size(); i++) {
this.listeners.get(i).barcodeRead(code);
}
}
/**
* Commence à ecouter les évenements clavier pour intercepter les codes barres
*/
public synchronized void start() {
if (this.timer == null) {
// init avant que les listeners s'en servent
this.timer = new Timer(getClass().getName(), true);
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(this);
System.err.println("BarcodeReader start : scan delay " + this.maxInterKeyDelay + " ms");
}
}
/**
* Stoppe l'écoute sur les évenements clavier
*/
public synchronized void stop() {
if (this.timer != null) {
System.err.println("BarcodeReader stop");
this.timer.cancel();
this.timer = null;
KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventDispatcher(this);
}
}
@Override
public boolean dispatchKeyEvent(KeyEvent e) {
if (!this.enable) {
return false;
}
if (this.task != null)
this.task.cancel();
final long t = e.getWhen();
if (this.firstTime < 0) {
this.firstTime = t;
}
int keyCode = e.getKeyCode();
final long delay = t - this.firstTime;
if (keyCode == KeyEvent.VK_BACK_SPACE || keyCode == KeyEvent.VK_DELETE || (delay > this.maxInterKeyDelay && keyCode != KeyEvent.VK_SHIFT)) {
// touche normale
if (this.debug) {
System.err.println("Touche normale " + keyCode);
}
this.eve.add(e);
redispatch();
return true;
}
final char keyChar = e.getKeyChar();
this.eve.add(e);
if (e.getID() == KeyEvent.KEY_RELEASED) {
if (keyCode == KeyEvent.VK_SHIFT) {
// rien
if (this.debug) {
System.err.println("SHIFT " + keyCode);
}
} else if (keyChar == ']') {
this.value += keyChar;
if (this.debug) {
System.err.println("]");
}
} else if (keyChar == '*' || keyChar == '$' || keyChar == '+' || keyChar == '/' || keyChar == '%' || keyChar == ' ') {
this.value += keyChar;
if (this.debug) {
System.err.println("KEY " + keyCode + " - " + keyChar);
}
} else if (keyCode >= KeyEvent.VK_0 && keyCode <= KeyEvent.VK_9 || keyCode >= KeyEvent.VK_A && keyCode <= KeyEvent.VK_Z) {
// from KeyEvent : same as ASCII
if (this.debug) {
System.err.println("[0-9] [A-Z] " + keyCode + " : " + keyChar);
}
this.value += (char) keyCode;
} else if (keyCode == KeyEvent.VK_ENTER && this.value.length() >= MIN_BARCODE_LENGTH) {
// fin de code barre
if (this.debug) {
System.err.println("BARCODE OK ENTER OR LENGHT " + keyCode + " length = " + this.value.length() + " min length =" + MIN_BARCODE_LENGTH);
}
this.value = this.value.trim();
fire(this.value);
reset();
} else if (this.mapCharacterFR.containsKey((int) keyChar)) {
if (this.debug) {
System.err.println("MAP DEFAULT FR CHAR " + keyChar + " WITH " + this.mapCharacterFR.get((int) keyChar));
}
this.value += this.mapCharacterFR.get((int) keyChar);
} else if (Character.isLetter(keyChar) || Character.isDigit(keyChar)) {
this.value += keyChar;
if (this.debug) {
System.err.println("LETTER OR DIGIT " + keyChar);
}
} else if (keyChar == 29) {
this.value += '\u001D';
if (this.debug) {
System.err.println("<GS>");
}
} else if (keyChar == KeyEvent.CHAR_UNDEFINED) {
System.err.println("CHAR_UNDEFINED");
} else {
// Caractere non code barre
if (this.debug) {
System.err.println("CHAR NON CODE BARRE keyCode:" + keyCode + " keyChar:" + keyChar);
}
redispatch();
}
// lance un timer s'il reste des evenements non dispatchés
if (!this.eve.isEmpty()) {
this.firstTime = t;
this.task = new TimerTask() {
@Override
public void run() {
redispatchLater();
}
};
this.timer.schedule(this.task, this.maxInterKeyDelay);
}
// si pas d'evenement, pas de temps associé
assert !this.eve.isEmpty() || this.firstTime == -1;
}
return true;
}
private void redispatchLater() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
redispatch();
}
});
}
private void redispatch() {
for (int i = 0; i < this.eve.size(); i++) {
final KeyEvent ee = this.eve.get(i);
KeyboardFocusManager.getCurrentKeyboardFocusManager().redispatchEvent(ee.getComponent(), ee);
for (int j = 0; j < this.listeners.size(); j++) {
this.listeners.get(j).keyReceived(ee);
}
}
reset();
}
private void reset() {
this.value = "";
this.eve.clear();
this.firstTime = -1;
}
public Map<Integer, String> getMapCharacterFR() {
return this.mapCharacterFR;
}
public void setDebug(boolean debug) {
this.debug = debug;
}
public static void main(String[] args) {
String delay = "80";
if (args.length > 0) {
delay = args[0];
}
final int d = Integer.parseInt(delay);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("BarCode reader");
System.out.println("Using inter key delay: " + d);
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
f.setTitle("Barcode reader test");
f.setContentPane(panel);
panel.setLayout(new GridBagLayout());
GridBagConstraints c = new DefaultGridBagConstraints();
final JLabel l = new JLabel("BarCode reader output :");
panel.add(l, c);
c.gridy++;
c.weighty = 1;
c.weightx = 1;
c.fill = GridBagConstraints.BOTH;
final ITextArea t1 = new ITextArea();
panel.add(new JScrollPane(t1), c);
BarcodeReader reader = new BarcodeReader(d);
reader.setDebug(true);
System.err.println("FR MAP");
for (Entry<Integer, String> string : reader.getMapCharacterFR().entrySet()) {
System.err.println(string.getKey() + " --> " + string.getValue());
}
reader.addBarcodeListener(new BarcodeListener() {
@Override
public void keyReceived(KeyEvent ee) {
System.err.println("BarcodeReader keyReceived() : " + ee);
}
@Override
public void barcodeRead(String code) {
t1.append("Barcode OK : '" + code + "'\n");
t1.append("Hex: " + StringUtils.bytesToHexString(code.getBytes()));
}
});
f.setSize(new Dimension(640, 480));
f.setLocationRelativeTo(null);
f.setVisible(true);
}
});
}
public void setEnabled(boolean b) {
this.enable = b;
}
}