/*
Реализация спецификаций CLDC версии 1.1 (JSR-139), MIDP версии 2.1 (JSR-118)
и других спецификаций для функционирования компактных приложений на языке
Java (мидлетов) в среде программного обеспечения Малик Эмулятор.
Copyright © 2016–2017, 2019–2023 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
*/
package malik.emulator.application;
public class KeyboardEvent extends InputEvent
{
public static final int KEY_BACKSPACE = 8;
public static final int KEY_TAB = 9;
public static final int KEY_ENTER = 13;
public static final int KEY_SHIFT = 16;
public static final int KEY_CTRL = 17;
public static final int KEY_ALT = 18;
public static final int KEY_PAUSE_BREAK = 19;
public static final int KEY_CAPS_LOCK = 20;
public static final int KEY_ESCAPE = 27;
public static final int KEY_SPACE = 32;
public static final int KEY_PAGE_UP = 33;
public static final int KEY_PAGE_DOWN = 34;
public static final int KEY_END = 35;
public static final int KEY_HOME = 36;
public static final int KEY_LEFT = 37;
public static final int KEY_UP = 38;
public static final int KEY_RIGHT = 39;
public static final int KEY_DOWN = 40;
public static final int KEY_INSERT = 45;
public static final int KEY_DELETE = 46;
public static final int KEY_0 = 48;
public static final int KEY_1 = 49;
public static final int KEY_2 = 50;
public static final int KEY_3 = 51;
public static final int KEY_4 = 52;
public static final int KEY_5 = 53;
public static final int KEY_6 = 54;
public static final int KEY_7 = 55;
public static final int KEY_8 = 56;
public static final int KEY_9 = 57;
public static final int KEY_A = 65;
public static final int KEY_B = 66;
public static final int KEY_C = 67;
public static final int KEY_D = 68;
public static final int KEY_E = 69;
public static final int KEY_F = 70;
public static final int KEY_G = 71;
public static final int KEY_H = 72;
public static final int KEY_I = 73;
public static final int KEY_J = 74;
public static final int KEY_K = 75;
public static final int KEY_L = 76;
public static final int KEY_M = 77;
public static final int KEY_N = 78;
public static final int KEY_O = 79;
public static final int KEY_P = 80;
public static final int KEY_Q = 81;
public static final int KEY_R = 82;
public static final int KEY_S = 83;
public static final int KEY_T = 84;
public static final int KEY_U = 85;
public static final int KEY_V = 86;
public static final int KEY_W = 87;
public static final int KEY_X = 88;
public static final int KEY_Y = 89;
public static final int KEY_Z = 90;
public static final int KEY_CONTEXT = 93;
public static final int KEY_NUM_0 = 96;
public static final int KEY_NUM_1 = 97;
public static final int KEY_NUM_2 = 98;
public static final int KEY_NUM_3 = 99;
public static final int KEY_NUM_4 = 100;
public static final int KEY_NUM_5 = 101;
public static final int KEY_NUM_6 = 102;
public static final int KEY_NUM_7 = 103;
public static final int KEY_NUM_8 = 104;
public static final int KEY_NUM_9 = 105;
public static final int KEY_NUM_STAR = 106;
public static final int KEY_NUM_PLUS = 107;
public static final int KEY_NUM_SEPARATOR = 108;
public static final int KEY_NUM_MINUS = 109;
public static final int KEY_NUM_DECIMAL = 110;
public static final int KEY_NUM_DIVIDE = 111;
public static final int KEY_F1 = 112;
public static final int KEY_F2 = 113;
public static final int KEY_F3 = 114;
public static final int KEY_F4 = 115;
public static final int KEY_F5 = 116;
public static final int KEY_F6 = 117;
public static final int KEY_F7 = 118;
public static final int KEY_F8 = 119;
public static final int KEY_F9 = 120;
public static final int KEY_F10 = 121;
public static final int KEY_F11 = 122;
public static final int KEY_F12 = 123;
public static final int KEY_F13 = 124;
public static final int KEY_F14 = 125;
public static final int KEY_F15 = 126;
public static final int KEY_F16 = 127;
public static final int KEY_F17 = 128;
public static final int KEY_F18 = 129;
public static final int KEY_F19 = 130;
public static final int KEY_F20 = 131;
public static final int KEY_F21 = 132;
public static final int KEY_F22 = 133;
public static final int KEY_F23 = 134;
public static final int KEY_F24 = 135;
public static final int KEY_NUM_LOCK = 144;
public static final int KEY_SCROLL_LOCK = 145;
public static final int KEY_LSHIFT = 160;
public static final int KEY_RSHIFT = 161;
public static final int KEY_LCTRL = 162;
public static final int KEY_RCTRL = 163;
public static final int KEY_LALT = 164;
public static final int KEY_RALT = 165;
public static final int KEY_SEMICOLON = 186;
public static final int KEY_EQUAL = 187;
public static final int KEY_COMMA = 188;
public static final int KEY_MINUS = 189;
public static final int KEY_PERIOD = 190;
public static final int KEY_SLASH = 191;
public static final int KEY_GRAVE = 192;
public static final int KEY_LBRACKET = 219;
public static final int KEY_BACKSLASH = 220;
public static final int KEY_RBRACKET = 221;
public static final int KEY_APOSTROPHE = 222;
public static final int ACTION_KEY_PRESSED = Requestable.ACTION_KEY_PRESSED;
public static final int ACTION_KEY_REPEATED = Requestable.ACTION_KEY_REPEATED;
public static final int ACTION_KEY_RELEASED = Requestable.ACTION_KEY_RELEASED;
private static final int OFFSET_KEY = 0x01;
private static final int OFFSET_CHAR = 0x02;
private static final int OFFSET_SOURCE = 0x03;
private static final int OFFSET_KEY_PRESSED = 0x04;
private static final int OFFSET_EVENT_TIME_LO = 0x0c;
private static final int OFFSET_EVENT_TIME_HI = 0x0d;
private static final int OFFSET_VIRTUAL_DATA_LO = 0x0e;
private static final int OFFSET_VIRTUAL_DATA_HI = 0x0f;
private static final int ELEMENTS_PER_STORY = 0x10;
private int base;
private int length;
private final int[] history;
public KeyboardEvent() {
this(0x0100);
}
public KeyboardEvent(int historyCapacity) {
if(historyCapacity < 0x0002) historyCapacity = 0x0002;
if(historyCapacity > 0x1000) historyCapacity = 0x1000;
this.base = (historyCapacity <<= 4) - ELEMENTS_PER_STORY;
this.length = ELEMENTS_PER_STORY;
this.history = new int[historyCapacity];
}
public int getSource() {
return history[base + OFFSET_SOURCE];
}
public long getEventTime() {
int b = base;
int[] h = history;
return (long) h[b + OFFSET_EVENT_TIME_LO] & 0x00000000ffffffffL | (long) h[b + OFFSET_EVENT_TIME_HI] << 32;
}
public long getVirtualData() {
int b = base;
int[] h = history;
return (long) h[b + OFFSET_VIRTUAL_DATA_LO] & 0x00000000ffffffffL | (long) h[b + OFFSET_VIRTUAL_DATA_HI] << 32;
}
public void addStory(int action, int key, int charCode, InputDevice device, int source, long virtualData) {
int[] history;
if(action != ACTION_KEY_REPEATED && action != ACTION_KEY_PRESSED && action != ACTION_KEY_RELEASED)
{
throw new IllegalArgumentException("KeyboardEvent.addStory: аргумент action имеет недопустимое значение.");
}
synchronized(history = this.history)
{
int capacity = history.length;
int oldBase = base;
int newBase = base = (oldBase + capacity - ELEMENTS_PER_STORY) % capacity;
int length = this.length;
long time = System.currentTimeMillis();
if(length < capacity) this.length = length + ELEMENTS_PER_STORY;
Array.copy(history, oldBase + OFFSET_KEY_PRESSED, history, newBase + OFFSET_KEY_PRESSED, 8);
if(key >= 0x00 && key <= 0xff)
{
int index = newBase + OFFSET_KEY_PRESSED + (key >> 5);
int bitkey = 1 << key;
if(action == ACTION_KEY_RELEASED)
{
history[index] &= ~bitkey;
}
else if((history[index] & bitkey) != 0)
{
action = ACTION_KEY_REPEATED;
}
else
{
action = ACTION_KEY_PRESSED;
history[index] |= bitkey;
}
}
this.device = device;
history[newBase] = action;
history[newBase + OFFSET_KEY] = key;
history[newBase + OFFSET_CHAR] = charCode;
history[newBase + OFFSET_SOURCE] = source;
history[newBase + OFFSET_EVENT_TIME_LO] = (int) time;
history[newBase + OFFSET_EVENT_TIME_HI] = (int) (time >> 32);
history[newBase + OFFSET_VIRTUAL_DATA_LO] = (int) virtualData;
history[newBase + OFFSET_VIRTUAL_DATA_HI] = (int) (virtualData >> 32);
}
}
public boolean historicalFromSource(int storyIndex, int source) {
int b;
int[] h;
if(storyIndex < 0 || storyIndex >= (length >> 4))
{
throw new IndexOutOfBoundsException("KeyboardEvent.historicalFromSource: аргумент storyIndex выходит из диапазона.");
}
h = history;
b = (base + (storyIndex << 4)) % h.length;
return (h[b + OFFSET_SOURCE] & source) == source;
}
public int historicalSource(int storyIndex) {
int b;
int[] h;
if(storyIndex < 0 || storyIndex >= (length >> 4))
{
throw new IndexOutOfBoundsException("KeyboardEvent.historicalSource: аргумент storyIndex выходит из диапазона.");
}
h = history;
b = (base + (storyIndex << 4)) % h.length;
return h[b + OFFSET_SOURCE];
}
public long historicalEventTime(int storyIndex) {
int b;
int[] h;
if(storyIndex < 0 || storyIndex >= (length >> 4))
{
throw new IndexOutOfBoundsException("KeyboardEvent.historicalEventTime: аргумент storyIndex выходит из диапазона.");
}
h = history;
b = (base + (storyIndex << 4)) % h.length;
return (long) h[b + OFFSET_EVENT_TIME_LO] & 0x00000000ffffffffL | (long) h[b + OFFSET_EVENT_TIME_HI] << 32;
}
public long historicalVirtualData(int storyIndex) {
int b;
int[] h;
if(storyIndex < 0 || storyIndex >= (length >> 4))
{
throw new IndexOutOfBoundsException("KeyboardEvent.historicalVirtualData: аргумент storyIndex выходит из диапазона.");
}
h = history;
b = (base + (storyIndex << 4)) % h.length;
return (long) h[b + OFFSET_VIRTUAL_DATA_LO] & 0x00000000ffffffffL | (long) h[b + OFFSET_VIRTUAL_DATA_HI] << 32;
}
public final boolean isKeyPressed(int key) {
return key >= 0x00 && key <= 0xff && (history[base + OFFSET_KEY_PRESSED + (key >> 5)] & (1 << key)) != 0;
}
public final boolean historicalKeyPressed(int storyIndex, int key) {
int b;
int[] h;
if(storyIndex < 0 || storyIndex >= (length >> 4))
{
throw new IndexOutOfBoundsException("KeyboardEvent.historicalKeyPressed: аргумент storyIndex выходит из диапазона.");
}
h = history;
b = (base + (storyIndex << 4)) % h.length;
return key >= 0x00 && key <= 0xff && (h[b + OFFSET_KEY_PRESSED + (key >> 5)] & (1 << key)) != 0;
}
public final int historicalCharCode(int storyIndex) {
int b;
int[] h;
if(storyIndex < 0 || storyIndex >= (length >> 4))
{
throw new IndexOutOfBoundsException("KeyboardEvent.historicalCharCode: аргумент storyIndex выходит из диапазона.");
}
h = history;
b = (base + (storyIndex << 4)) % h.length;
return h[b + OFFSET_CHAR];
}
public final int historicalAction(int storyIndex) {
int b;
int[] h;
if(storyIndex < 0 || storyIndex >= (length >> 4))
{
throw new IndexOutOfBoundsException("KeyboardEvent.historicalAction: аргумент storyIndex выходит из диапазона.");
}
h = history;
b = (base + (storyIndex << 4)) % h.length;
return h[b];
}
public final int historicalKey(int storyIndex) {
int b;
int[] h;
if(storyIndex < 0 || storyIndex >= (length >> 4))
{
throw new IndexOutOfBoundsException("KeyboardEvent.historicalKey: аргумент storyIndex выходит из диапазона.");
}
h = history;
b = (base + (storyIndex << 4)) % h.length;
return h[b + OFFSET_KEY];
}
public final int historyCapacity() {
return history.length >> 4;
}
public final int historyLength() {
return length >> 4;
}
public final int getCharCode() {
return history[base + OFFSET_CHAR];
}
public final int getAction() {
return history[base];
}
public final int getKey() {
return history[base + OFFSET_KEY];
}
}