aboutsummaryrefslogtreecommitdiffstats
path: root/plugins/linux/src/native/net_java_games_input_LinuxEventDevice.c
blob: 044c3ddf2a11e97870397fc313424bc0576b5658 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
/*
 * %W% %E%
 *
 * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
/*****************************************************************************
* Copyright (c) 2003 Sun Microsystems, Inc.  All Rights Reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistribution of source code must retain the above copyright notice,
*   this list of conditions and the following disclaimer.
*
* - Redistribution in binary form must reproduce the above copyright notice,
*   this list of conditions and the following disclaimer in the documentation
*   and/or other materails provided with the distribution.
*
* Neither the name Sun Microsystems, Inc. or the names of the contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
* ANY IMPLIED WARRANT OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
* NON-INFRINGEMEN, ARE HEREBY EXCLUDED.  SUN MICROSYSTEMS, INC. ("SUN") AND
* ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS
* A RESULT OF USING, MODIFYING OR DESTRIBUTING THIS SOFTWARE OR ITS 
* DERIVATIVES.  IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
* REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
* INCIDENTAL OR PUNITIVE DAMAGES.  HOWEVER CAUSED AND REGARDLESS OF THE THEORY
* OF LIABILITY, ARISING OUT OF THE USE OF OUR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed or intended for us in
* the design, construction, operation or maintenance of any nuclear facility
*
*****************************************************************************/

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/input.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include "util.h"
#include "net_java_games_input_LinuxEventDevice.h"

JNIEXPORT jlong JNICALL Java_net_java_games_input_LinuxEventDevice_nOpen(JNIEnv *env, jclass unused, jstring path, jboolean rw_flag) {
	const char *path_str = (*env)->GetStringUTFChars(env, path, NULL);
	if (path_str == NULL)
		return -1;
	int flags = rw_flag == JNI_TRUE ? O_RDWR : O_RDONLY;
	flags = flags | O_NONBLOCK;
	int fd = open(path_str, flags);
	if (fd == -1)
		throwIOException(env, "Failed to open device %s (%d)\n", path_str, errno);
	(*env)->ReleaseStringUTFChars(env, path, path_str);
	return fd;
}

JNIEXPORT void JNICALL Java_net_java_games_input_LinuxEventDevice_nClose(JNIEnv *env, jclass unused, jlong fd_address) {
	int fd = (int)fd_address;
	int result = close(fd);
	if (result == -1)
		throwIOException(env, "Failed to close device (%d)\n", errno);
}

JNIEXPORT jstring JNICALL Java_net_java_games_input_LinuxEventDevice_nGetName(JNIEnv *env, jclass unused, jlong fd_address) {
#define BUFFER_SIZE 1024
	int fd = (int)fd_address;
	char device_name[BUFFER_SIZE];
	
	if (ioctl(fd, EVIOCGNAME(BUFFER_SIZE), device_name) == -1) {
		throwIOException(env, "Failed to get device name (%d)\n", errno);
		return NULL;
	}
	jstring jstr = (*env)->NewStringUTF(env, device_name);
	return jstr;
}

JNIEXPORT void JNICALL Java_net_java_games_input_LinuxEventDevice_nGetKeyStates(JNIEnv *env, jclass unused, jlong fd_address, jbyteArray bits_array) {
	int fd = (int)fd_address;
	jsize len = (*env)->GetArrayLength(env, bits_array);
	jbyte *bits = (*env)->GetByteArrayElements(env, bits_array, NULL);
	if (bits == NULL)
		return;
	int res = ioctl(fd, EVIOCGKEY(len), bits);
	(*env)->ReleaseByteArrayElements(env, bits_array, bits, 0);
	if (res == -1)
		throwIOException(env, "Failed to get device key states (%d)\n", errno);
}

JNIEXPORT jint JNICALL Java_net_java_games_input_LinuxEventDevice_nGetVersion(JNIEnv *env, jclass unused, jlong fd_address) {
	int fd = (int)fd_address;
	int version;
	if (ioctl(fd, EVIOCGVERSION, &version) == -1) {
		throwIOException(env, "Failed to get device version (%d)\n", errno);
		return -1;
	}
	return version;
}

JNIEXPORT jint JNICALL Java_net_java_games_input_LinuxEventDevice_nGetNumEffects(JNIEnv *env, jclass unused, jlong fd_address) {
	int fd = (int)fd_address;
	int num_effects;
	if (ioctl(fd, EVIOCGEFFECTS, &num_effects) == -1) {
		throwIOException(env, "Failed to get number of device effects (%d)\n", errno);
		return -1;
	}
	return num_effects;
}

JNIEXPORT void JNICALL Java_net_java_games_input_LinuxEventDevice_nGetBits(JNIEnv *env, jclass unused, jlong fd_address, jint evtype, jbyteArray bits_array) {
	int fd = (int)fd_address;
	jsize len = (*env)->GetArrayLength(env, bits_array);
	jbyte *bits = (*env)->GetByteArrayElements(env, bits_array, NULL);
	if (bits == NULL)
		return;
	int res = ioctl(fd, EVIOCGBIT(evtype, len), bits);
	(*env)->ReleaseByteArrayElements(env, bits_array, bits, 0);
	if (res == -1)
		throwIOException(env, "Failed to get device bits (%d)\n", errno);
}

JNIEXPORT jobject JNICALL Java_net_java_games_input_LinuxEventDevice_nGetInputID(JNIEnv *env, jclass unused, jlong fd_address) {
	int fd = (int)fd_address;
	jclass input_id_class = (*env)->FindClass(env, "net/java/games/input/LinuxInputID");
	if (input_id_class == NULL)
		return NULL;
	jmethodID input_id_constructor = (*env)->GetMethodID(env, input_id_class, "<init>", "(IIII)V");
	if (input_id_constructor == NULL)
		return NULL;
	struct input_id id;
	int result = ioctl(fd, EVIOCGID, &id);
	if (result == -1) {
		throwIOException(env, "Failed to get input id for device (%d)\n", errno);
		return NULL;
	}
	return (*env)->NewObject(env, input_id_class, input_id_constructor, (jint)id.bustype, (jint)id.vendor, (jint)id.product, (jint)id.version);
}

JNIEXPORT void JNICALL Java_net_java_games_input_LinuxEventDevice_nGetAbsInfo(JNIEnv *env, jclass unused, jlong fd_address, jint abs_axis, jobject abs_info_return) {
	int fd = (int)fd_address;
	jclass abs_info_class = (*env)->GetObjectClass(env, abs_info_return);
	if (abs_info_class == NULL)
		return;
	jmethodID abs_info_set = (*env)->GetMethodID(env, abs_info_class, "set", "(IIIII)V");
	if (abs_info_set == NULL)
		return;
	struct input_absinfo abs_info;
	int result = ioctl(fd, EVIOCGABS(abs_axis), &abs_info);
	if (result == -1) {
		throwIOException(env, "Failed to get abs info for axis (%d)\n", errno);
		return;
	}
	(*env)->CallVoidMethod(env, abs_info_return, abs_info_set, (jint)abs_info.value, (jint)abs_info.minimum, (jint)abs_info.maximum, (jint)abs_info.fuzz, (jint)abs_info.flat);
}

JNIEXPORT jboolean JNICALL Java_net_java_games_input_LinuxEventDevice_nGetNextEvent(JNIEnv *env, jclass unused, jlong fd_address, jobject linux_event_return) {
	int fd = (int)fd_address;
	jclass linux_event_class = (*env)->GetObjectClass(env, linux_event_return);
	if (linux_event_class == NULL)
		return JNI_FALSE;
	jmethodID linux_event_set = (*env)->GetMethodID(env, linux_event_class, "set", "(JJIII)V");
	if (linux_event_set == NULL)
		return JNI_FALSE;
	struct input_event event;
	if (read(fd, &event, sizeof(struct input_event)) == -1) {
		if (errno == EAGAIN)
			return JNI_FALSE;
		throwIOException(env, "Failed to read next device event (%d)\n", errno);
		return JNI_FALSE;
	}
	(*env)->CallVoidMethod(env, linux_event_return, linux_event_set, (jlong)event.time.tv_sec, (jlong)event.time.tv_usec, (jint)event.type, (jint)event.code, (jint)event.value);
	return JNI_TRUE;
}

JNIEXPORT jint JNICALL Java_net_java_games_input_LinuxEventDevice_nUploadRumbleEffect(JNIEnv *env, jclass unused, jlong fd_address, jint id, jint direction, jint trigger_button, jint trigger_interval, jint replay_length, jint replay_delay, jint strong_magnitude, jint weak_magnitude) {
	int fd = (int)fd_address;
	struct ff_effect effect;

	effect.type = FF_RUMBLE;
	effect.id = id;
	effect.trigger.button = trigger_button;
	effect.trigger.interval = trigger_interval;
	effect.replay.length = replay_length;
	effect.replay.delay = replay_delay;
	effect.direction = direction;
	effect.u.rumble.strong_magnitude = strong_magnitude;
	effect.u.rumble.weak_magnitude = weak_magnitude;

	if (ioctl(fd, EVIOCSFF, &effect) == -1) {
		throwIOException(env, "Failed to upload effect (%d)\n", errno);
		return -1;
	}
	return effect.id;
}

JNIEXPORT jint JNICALL Java_net_java_games_input_LinuxEventDevice_nUploadConstantEffect(JNIEnv *env, jclass unused, jlong fd_address, jint id, jint direction, jint trigger_button, jint trigger_interval, jint replay_length, jint replay_delay, jint constant_level, jint constant_env_attack_length, jint constant_env_attack_level, jint constant_env_fade_length, jint constant_env_fade_level) {
	int fd = (int)fd_address;
	struct ff_effect effect;

	effect.type = FF_CONSTANT;
	effect.id = id;
	effect.trigger.button = trigger_button;
	effect.trigger.interval = trigger_interval;
	effect.replay.length = replay_length;
	effect.replay.delay = replay_delay;
	effect.direction = direction;
	effect.u.constant.level = constant_level;
	effect.u.constant.envelope.attack_length = constant_env_attack_length;
	effect.u.constant.envelope.attack_level = constant_env_attack_level;
	effect.u.constant.envelope.fade_length = constant_env_fade_length;
	effect.u.constant.envelope.fade_level = constant_env_fade_level;

	if (ioctl(fd, EVIOCSFF, &effect) == -1) {
		throwIOException(env, "Failed to upload effect (%d)\n", errno);
		return -1;
	}
	return effect.id;
}

JNIEXPORT void JNICALL Java_net_java_games_input_LinuxEventDevice_nWriteEvent(JNIEnv *env, jclass unused, jlong fd_address, jint type, jint code, jint value) {
	int fd = (int)fd_address;
	struct input_event event;
	event.type = type;
	event.code = code;
	event.value = value;

	if (write(fd, &event, sizeof(event)) == -1) {
		throwIOException(env, "Failed to write to device (%d)\n", errno);
	}
}

JNIEXPORT void JNICALL Java_net_java_games_input_LinuxEventDevice_nEraseEffect(JNIEnv *env, jclass unused, jlong fd_address, jint ff_id) {
	int fd = (int)fd_address;
	int ff_id_int = ff_id;

	if (ioctl(fd, EVIOCRMFF, &ff_id_int) == -1)
		throwIOException(env, "Failed to erase effect (%d)\n", errno);
}

JNIEXPORT jint JNICALL Java_net_java_games_input_LinuxEventDevice_nGrab(JNIEnv *env, jclass unused, jlong fd_address, jint do_grab) {
        int fd = (int)fd_address;
        int grab = (int)do_grab;
<<<<<<< HEAD
        int version;
        if (ioctl(fd,EVIOCGRAB,do_grab) == -1){
=======
        if (ioctl(fd,EVIOCGRAB,grab) == -1){
>>>>>>> 835f3b36964d5a757ab4baea8240f1d56a97e375
                throwIOException(env, "Failed to grab device (%d)\n", errno);
            return -1;
	}
        return 1;
}