/*
Реализация спецификаций 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 PointerEvent extends InputEvent
{
public static final int BUTTON_MAIN = 0;
public static final int BUTTON_AUX_1 = 1;
public static final int BUTTON_AUX_2 = 2;
public static final int BUTTON_AUX_3 = 3;
public static final int BUTTON_AUX_4 = 4;
public static final int BUTTON_AUX_5 = 5;
public static final int BUTTON_AUX_6 = 6;
public static final int BUTTON_AUX_7 = 7;
public static final int BUTTON_AUX_8 = 8;
public static final int BUTTON_AUX_9 = 9;
public static final int BUTTON_AUX_10 = 10;
public static final int BUTTON_AUX_11 = 11;
public static final int BUTTON_AUX_12 = 12;
public static final int BUTTON_WHEEL = 13;
public static final int BUTTON_WHEEL_UP = 14;
public static final int BUTTON_WHEEL_DOWN = 15;
public static final int ACTION_POINTER_PRESSED = Requestable.ACTION_POINTER_PRESSED;
public static final int ACTION_POINTER_DRAGGED = Requestable.ACTION_POINTER_DRAGGED;
public static final int ACTION_POINTER_RELEASED = Requestable.ACTION_POINTER_RELEASED;
public static final int ACTION_BUTTON_PRESSED = Requestable.ACTION_BUTTON_PRESSED;
public static final int ACTION_BUTTON_RELEASED = Requestable.ACTION_BUTTON_RELEASED;
private static final int OFFSET_BUTTON = 0x01;
private static final int OFFSET_COORDS = 0x02;
private static final int OFFSET_SOURCE = 0x03;
private static final int OFFSET_EVENT_TIME_LO = 0x04;
private static final int OFFSET_EVENT_TIME_HI = 0x05;
private static final int OFFSET_VIRTUAL_DATA_LO = 0x06;
private static final int OFFSET_VIRTUAL_DATA_HI = 0x07;
private static final int ELEMENTS_PER_STORY = 0x08;
private int tx;
private int ty;
private int base;
private int length;
private final int[] history;
public PointerEvent() {
this(0x0100);
}
public PointerEvent(int historyCapacity) {
if(historyCapacity < 0x0002) historyCapacity = 0x0002;
if(historyCapacity > 0x1000) historyCapacity = 0x1000;
this.base = (historyCapacity <<= 3) - 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 button, int rawX, int rawY, InputDevice device, int source, long virtualData) {
int[] history;
if(action == ACTION_BUTTON_PRESSED) action = ACTION_POINTER_PRESSED;
if(action == ACTION_BUTTON_RELEASED) action = ACTION_POINTER_RELEASED;
if(action != ACTION_POINTER_DRAGGED && action != ACTION_POINTER_PRESSED && action != ACTION_POINTER_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;
history[newBase] = history[oldBase] & 0xffff0000;
if(action == ACTION_POINTER_DRAGGED)
{
button = -1;
}
else if(button >= 0x00 && button <= 0x0f)
{
int index = newBase;
int bitbutton = 1 << (button + 0x10);
switch(action)
{
case ACTION_POINTER_PRESSED:
if(((history[index] |= bitbutton) & ~bitbutton) != 0) action = ACTION_BUTTON_PRESSED;
break;
case ACTION_POINTER_RELEASED:
if((history[index] &= ~bitbutton) != 0) action = ACTION_BUTTON_RELEASED;
break;
}
}
this.device = device;
history[newBase] = history[newBase] & 0xffff0000 | action;
history[newBase + OFFSET_BUTTON] = button;
history[newBase + OFFSET_COORDS] = rawX & 0xffff | rawY << 0x0010;
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 void translateReset() {
tx = 0;
ty = 0;
}
public void translate(int deltaX, int deltaY) {
tx += deltaX;
ty += deltaY;
}
public void translateTo(int rawX, int rawY) {
tx = rawX;
ty = rawY;
}
public boolean historicalFromSource(int storyIndex, int source) {
int b;
int[] h;
if(storyIndex < 0 || storyIndex >= (length >> 3))
{
throw new IndexOutOfBoundsException("PointerEvent.historicalFromSource: аргумент storyIndex выходит из диапазона.");
}
h = history;
b = (base + (storyIndex << 3)) % h.length;
return (h[b + OFFSET_SOURCE] & source) == source;
}
public int historicalSource(int storyIndex) {
int b;
int[] h;
if(storyIndex < 0 || storyIndex >= (length >> 3))
{
throw new IndexOutOfBoundsException("PointerEvent.historicalSource: аргумент storyIndex выходит из диапазона.");
}
h = history;
b = (base + (storyIndex << 3)) % h.length;
return h[b + OFFSET_SOURCE];
}
public int getTranslateX() {
return tx;
}
public int getTranslateY() {
return ty;
}
public long historicalEventTime(int storyIndex) {
int b;
int[] h;
if(storyIndex < 0 || storyIndex >= (length >> 3))
{
throw new IndexOutOfBoundsException("PointerEvent.historicalEventTime: аргумент storyIndex выходит из диапазона.");
}
h = history;
b = (base + (storyIndex << 3)) % 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 >> 3))
{
throw new IndexOutOfBoundsException("PointerEvent.historicalVirtualData: аргумент storyIndex выходит из диапазона.");
}
h = history;
b = (base + (storyIndex << 3)) % h.length;
return (long) h[b + OFFSET_VIRTUAL_DATA_LO] & 0x00000000ffffffffL | (long) h[b + OFFSET_VIRTUAL_DATA_HI] << 32;
}
public final boolean isButtonPressed(int button) {
return button >= 0x00 && button <= 0x0f && (history[base] & (1 << (button + 0x10))) != 0;
}
public final boolean historicalButtonPressed(int storyIndex, int button) {
int b;
int[] h;
if(storyIndex < 0 || storyIndex >= (length >> 3))
{
throw new IndexOutOfBoundsException("PointerEvent.historicalButtonPressed: аргумент storyIndex выходит из диапазона.");
}
h = history;
b = (base + (storyIndex << 3)) % h.length;
return button >= 0x00 && button <= 0x0f && (h[b] & (1 << (button + 0x10))) != 0;
}
public final int historicalButton(int storyIndex) {
int b;
int[] h;
if(storyIndex < 0 || storyIndex >= (length >> 3))
{
throw new IndexOutOfBoundsException("PointerEvent.historicalButton: аргумент storyIndex выходит из диапазона.");
}
h = history;
b = (base + (storyIndex << 3)) % h.length;
return h[b + OFFSET_BUTTON];
}
public final int historicalAction(int storyIndex) {
int b;
int[] h;
if(storyIndex < 0 || storyIndex >= (length >> 3))
{
throw new IndexOutOfBoundsException("PointerEvent.historicalAction: аргумент storyIndex выходит из диапазона.");
}
h = history;
b = (base + (storyIndex << 3)) % h.length;
return h[b] & 0xffff;
}
public final int historicalRawX(int storyIndex) {
int b;
int[] h;
if(storyIndex < 0 || storyIndex >= (length >> 3))
{
throw new IndexOutOfBoundsException("PointerEvent.historicalRawX: аргумент storyIndex выходит из диапазона.");
}
h = history;
b = (base + (storyIndex << 3)) % h.length;
return (short) h[b + OFFSET_COORDS];
}
public final int historicalRawY(int storyIndex) {
int b;
int[] h;
if(storyIndex < 0 || storyIndex >= (length >> 3))
{
throw new IndexOutOfBoundsException("PointerEvent.historicalRawY: аргумент storyIndex выходит из диапазона.");
}
h = history;
b = (base + (storyIndex << 3)) % h.length;
return (h[b + OFFSET_COORDS] >> 16);
}
public final int historicalX(int storyIndex) {
int b;
int[] h;
if(storyIndex < 0 || storyIndex >= (length >> 3))
{
throw new IndexOutOfBoundsException("PointerEvent.historicalX: аргумент storyIndex выходит из диапазона.");
}
h = history;
b = (base + (storyIndex << 3)) % h.length;
return (short) h[b + OFFSET_COORDS] - tx;
}
public final int historicalY(int storyIndex) {
int b;
int[] h;
if(storyIndex < 0 || storyIndex >= (length >> 3))
{
throw new IndexOutOfBoundsException("PointerEvent.historicalY: аргумент storyIndex выходит из диапазона.");
}
h = history;
b = (base + (storyIndex << 3)) % h.length;
return (h[b + OFFSET_COORDS] >> 16) - ty;
}
public final int historyCapacity() {
return history.length >> 3;
}
public final int historyLength() {
return length >> 3;
}
public final int getButton() {
return history[base + OFFSET_BUTTON];
}
public final int getAction() {
return history[base] & 0xffff;
}
public final int getRawX() {
return (short) history[base + OFFSET_COORDS];
}
public final int getRawY() {
return (history[base + OFFSET_COORDS] >> 16);
}
public final int getX() {
return (short) history[base + OFFSET_COORDS] - tx;
}
public final int getY() {
return (history[base + OFFSET_COORDS] >> 16) - ty;
}
}