/* scale to Penpartner resolution */
s->x = (x * 5040 / 0x7FFF);
s->y = (y * 3780 / 0x7FFF);
- s->dz += dz;
+ //s->dz += dz;
+ s->dz = dz;
s->buttons_state = buttons_state;
s->changed = 1;
}
return 0;
buf[0] = s->mode;
- buf[5] = 0x00 | (b & 0xf0);
+ buf[5] = s->dz; //00 | (b & 0xf0);
buf[1] = s->x & 0xff;
buf[2] = s->x >> 8;
buf[3] = s->y & 0xff;
static int gui_key_modifier_pressed;
static int gui_keysym;
static kbd_layout_t *kbd_layout = NULL;
+extern multi_touch_state qemu_mts;
static uint8_t gtk_keyevent_to_keycode_generic(const GdkEventKey *event)
static void gtk_process_key(GdkEventKey *event)
{
int keycode, v;
+ int i;
if (event->keyval == GDK_Pause) {
/* specific case */
case 0x2a: /* Left Shift */
case 0x36: /* Right Shift */
case 0x1d: /* Left CTRL */
+ if (event->type == GDK_KEY_RELEASE) {
+ qemu_mts.multitouch_enable = 0;
+
+ if (qemu_mts.finger_cnt > 0) {
+ for (i = 0; i < qemu_mts.finger_cnt; i++) {
+ kbd_mouse_event(qemu_mts.finger_slot[i].dx, qemu_mts.finger_slot[i].dy, i, 0);
+ }
+ qemu_mts.finger_cnt = 0;
+ }
+ } else {
+ qemu_mts.multitouch_enable = 1;
+ }
+
case 0x9d: /* Right CTRL */
case 0x38: /* Left ALT */
case 0xb8: /* Right ALT */
return TRUE;
}
+static void do_multitouch_prossesing(int x, int y, int dx, int dy, int dz, int touch_type)
+{
+ if (touch_type == 1 && qemu_mts.finger_cnt < MAX_MULTI_TOUCH_CNT) {
+ qemu_mts.finger_slot[qemu_mts.finger_cnt].x = x; //skin position
+ qemu_mts.finger_slot[qemu_mts.finger_cnt].y = y;
+ qemu_mts.finger_slot[qemu_mts.finger_cnt].dx = dx; //lcd position
+ qemu_mts.finger_slot[qemu_mts.finger_cnt].dy = dy;
+
+ dz = qemu_mts.finger_cnt;
+ //fprintf(stderr, "!!!!! dx=%d, dy=%d, dz=%d, touch_type=%d\n", dx, dy, dz, touch_type);
+ kbd_mouse_event(dx, dy, dz, 1);
+
+ qemu_mts.finger_cnt++;
+ } else if (touch_type == 1 && qemu_mts.finger_cnt == MAX_MULTI_TOUCH_CNT) {
+ //move last touch point
+ qemu_mts.finger_slot[MAX_MULTI_TOUCH_CNT - 1].x = x;
+ qemu_mts.finger_slot[MAX_MULTI_TOUCH_CNT - 1].y = y;
+ qemu_mts.finger_slot[MAX_MULTI_TOUCH_CNT - 1].dx = dx;
+ qemu_mts.finger_slot[MAX_MULTI_TOUCH_CNT - 1].dy = dy;
+ dz = qemu_mts.finger_cnt - 1;
+ //fprintf(stderr, "!!!!! dx=%d, dy=%d, dz=%d, touch_type=%d\n", dx, dy, dz, touch_type);
+ kbd_mouse_event(dx, dy, dz, 1);
+ }
+}
+
static int button_status = -1;
-static void touch_shoot_for_type(int x, int y, int lcd_status, int touch_type)
+static void touch_shoot_for_type(GtkWidget *widget, int x, int y, int lcd_status, int touch_type)
{
int dx, dy, dz = 0, lcd_height, lcd_width;
+ int i;
GtkWidget *pWidget = NULL;
GtkWidget *popup_menu = get_widget(EMULATOR_ID, POPUP_MENU);
lcd_height = (int)(PHONE.mode[UISTATE.current_mode].lcd_list[lcd_status].lcd_region.h);
/* when portrait */
pWidget = g_object_get_data((GObject *) popup_menu, PORTRAIT);
- if(pWidget && GTK_IS_CHECK_MENU_ITEM(pWidget)) {
- if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(pWidget)) == TRUE) /* touch drag process */
- kbd_mouse_event(dx, dy, dz, touch_type);
+ if (pWidget && GTK_IS_CHECK_MENU_ITEM(pWidget)) {
+ if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(pWidget)) == TRUE) { /* touch drag process */
+ if (qemu_mts.multitouch_enable == 1) {
+ /* ctrl key pressed */
+ do_multitouch_prossesing(x, y, dx, dy, dz, touch_type);
+ } else {
+ kbd_mouse_event(dx, dy, dz, touch_type);
+ }
+ }
}
- else
- kbd_mouse_event(dx, dy, dz, touch_type);
+
/* when landscape */
pWidget = g_object_get_data((GObject *) popup_menu, LANDSCAPE);
- if(pWidget && GTK_IS_CHECK_MENU_ITEM(pWidget)) {
+ if (pWidget && GTK_IS_CHECK_MENU_ITEM(pWidget)) {
if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(pWidget)) == TRUE) {
- if (qemu_arch_is_arm()){
+ if (qemu_arch_is_arm()) {
/* here dx comes dy and since it is (dy - 0x7FFF - lcd_height - 1) * -1) becomes dx
am subtracting 0x7fff because it was multiplied earlier, No idea why 0x7fff is used
Similar comments for other rotations
*/
+ //todo : multitouch
kbd_mouse_event(((dy - 0x7FFF - lcd_height - 1) * -1) , dx, dz, touch_type);
- }
- else
- {
- kbd_mouse_event(dx, dy, dz, touch_type);
+ } else {
+ if (qemu_mts.multitouch_enable == 1) {
+ /* ctrl key pressed */
+ do_multitouch_prossesing(x, y, dx, dy, dz, touch_type);
+ } else {
+ kbd_mouse_event(dx, dy, dz, touch_type);
+ }
}
}
}
pWidget = g_object_get_data((GObject *) popup_menu, REVERSE_PORTRAIT);
if(pWidget && GTK_IS_CHECK_MENU_ITEM(pWidget)) {
if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(pWidget)) == TRUE) {
- if (qemu_arch_is_arm())
- kbd_mouse_event((dx - 0x7FFF - lcd_width - 1)*-1, (dy -0x7FFF) * -1, dz, touch_type);
- else
+ if (qemu_arch_is_arm()) {
+ //todo : multitouch
+ kbd_mouse_event((dx - 0x7FFF - lcd_width - 1)*-1, (dy -0x7FFF) * -1, dz, touch_type);
+ } else {
+ if (qemu_mts.multitouch_enable == 1) {
+ /* ctrl key pressed */
+ do_multitouch_prossesing(x, y, dx, dy, dz, touch_type);
+ } else {
kbd_mouse_event(dx, dy, dz, touch_type);
+ }
+ }
}
}
/* when reverse landscape */
pWidget = g_object_get_data((GObject *) popup_menu, REVERSE_LANDSCAPE);
- if(pWidget && GTK_IS_CHECK_MENU_ITEM(pWidget)) {
+ if (pWidget && GTK_IS_CHECK_MENU_ITEM(pWidget)) {
if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(pWidget)) == TRUE) {
- if (qemu_arch_is_arm())
- kbd_mouse_event(dy, (dx - 0x7FFF)*-1, dz, touch_type);
- else
+ if (qemu_arch_is_arm()) {
+ //todo : multitouch
+ kbd_mouse_event(dy, (dx - 0x7FFF)*-1, dz, touch_type);
+ } else {
+ if (qemu_mts.multitouch_enable == 1) {
+ /* ctrl key pressed */
+ do_multitouch_prossesing(x, y, dx, dy, dz, touch_type);
+ } else {
kbd_mouse_event(dx, dy, dz, touch_type);
+ }
+ }
}
}
}
if (event->type == GDK_MOTION_NOTIFY)
if (lcd_status == LCD_REGION || lcd_status == DUAL_LCD_REGION)
- touch_shoot_for_type(dx, dy, lcd_status, TOUCH_DRAG);
+ touch_shoot_for_type(widget, dx, dy, lcd_status, TOUCH_DRAG);
}
/* 4. when event press */
if (lcd_status == LCD_REGION || lcd_status == DUAL_LCD_REGION) {
lcd_press_flag = TRUE;
- touch_shoot_for_type(dx, dy, lcd_status, TOUCH_PRESS);
+ touch_shoot_for_type(widget, dx, dy, lcd_status, TOUCH_PRESS);
}
/* 5.2 when event is not in lcd region (keycode region) */
/* 5.1 when event is in lcd region (touch region) */
if (lcd_status == LCD_REGION || lcd_status == DUAL_LCD_REGION)
- touch_shoot_for_type(dx, dy, lcd_status, TOUCH_RELEASE);
+ touch_shoot_for_type(widget, dx, dy, lcd_status, TOUCH_RELEASE);
/* 5.2 when event is not in lcd region (keycode region) */
#include "qemu_gtk_widget.h"
#include "utils.h"
#include <pthread.h>
+#include "cursor_left_ptr.xpm"
#include "debug_ch.h"
#include "../ui/sdl_rotate.h"
static int widget_exposed;
int qemu_state_initialized = 0;
static pthread_mutex_t sdl_mutex = PTHREAD_MUTEX_INITIALIZER;
+static SDL_Cursor* sdl_cursor_normal;
+multi_touch_state qemu_mts;
#define SDL_THREAD
}
+static SDL_Cursor *sdl_cursor_init(const char *image[])
+{
+ int i, row, col;
+ Uint8 data[4*32];
+ Uint8 mask[4*32];
+ int w, h;
+
+ sscanf(image[0], "%d %d", &w, &h);
+
+ i = -1;
+ for ( row=0; row<32; ++row ) {
+ for ( col=0; col<32; ++col ) {
+ if ( col % 8 ) {
+ data[i] <<= 1;
+ mask[i] <<= 1;
+ } else {
+ ++i;
+ data[i] = mask[i] = 0;
+ }
+ switch (image[4+row][col]) {
+ case 'X':
+ data[i] |= 0x01;
+ mask[i] |= 0x01;
+ break;
+ case '.':
+ mask[i] |= 0x01;
+ break;
+ case ' ':
+ break;
+ }
+ }
+ }
+ return SDL_CreateCursor(data, mask, 32, 32, 0, 0);
+}
+
+/*
+ * This is a 32-bit pixel function created with help from this
+* website: http://www.libsdl.org/intro.en/usingvideo.html
+*
+* You will need to make changes if you want it to work with
+* 8-, 16- or 24-bit surfaces. Consult the above website for
+* more information.
+*/
+void sdl_set_pixel(SDL_Surface *surface, int x, int y, Uint32 pixel) {
+ Uint8 *target_pixel = (Uint8 *)surface->pixels + y * surface->pitch + x * 4;
+ *(Uint32 *)target_pixel = pixel;
+}
+
+/*
+* This is an implementation of the Midpoint Circle Algorithm
+* found on Wikipedia at the following link:
+*
+* http://en.wikipedia.org/wiki/Midpoint_circle_algorithm
+*
+* The algorithm elegantly draws a circle quickly, using a
+* set_pixel function for clarity.
+*/
+void sdl_draw_circle(SDL_Surface *surface, int cx, int cy, int radius, Uint32 pixel) {
+ int error = -radius;
+ int x = radius;
+ int y = 0;
+
+ while (x >= y)
+ {
+ sdl_set_pixel(surface, cx + x, cy + y, pixel);
+ sdl_set_pixel(surface, cx + y, cy + x, pixel);
+
+ if (x != 0)
+ {
+ sdl_set_pixel(surface, cx - x, cy + y, pixel);
+ sdl_set_pixel(surface, cx + y, cy - x, pixel);
+ }
+
+ if (y != 0)
+ {
+ sdl_set_pixel(surface, cx + x, cy - y, pixel);
+ sdl_set_pixel(surface, cx - y, cy + x, pixel);
+ }
+
+ if (x != 0 && y != 0)
+ {
+ sdl_set_pixel(surface, cx - x, cy - y, pixel);
+ sdl_set_pixel(surface, cx - y, cy - x, pixel);
+ }
+
+ error += y;
+ ++y;
+ error += y;
+
+ if (error >= 0)
+ {
+ --x;
+ error -= x;
+ error -= x;
+ }
+ }
+}
+
+/*
+ * SDL_Surface 32-bit circle-fill algorithm without using trig
+*
+* While I humbly call this "Celdecea's Method", odds are that the
+* procedure has already been documented somewhere long ago. All of
+* the circle-fill examples I came across utilized trig functions or
+* scanning neighbor pixels. This algorithm identifies the width of
+* a semi-circle at each pixel height and draws a scan-line covering
+* that width.
+*
+* The code is not optimized but very fast, owing to the fact that it
+* alters pixels in the provided surface directly rather than through
+* function calls.
+*
+* WARNING: This function does not lock surfaces before altering, so
+* use SDL_LockSurface in any release situation.
+*/
+static void sdl_fill_circle(SDL_Surface *surface, int cx, int cy, int radius, Uint32 pixel)
+{
+ // Note that there is more to altering the bitrate of this
+ // method than just changing this value. See how pixels are
+ // altered at the following web page for tips:
+ // http://www.libsdl.org/intro.en/usingvideo.html
+ const int bpp = 4;
+ double dy;
+
+ double r = (double)radius;
+
+ for (dy = 1; dy <= r; dy += 1.0)
+ {
+ // This loop is unrolled a bit, only iterating through half of the
+ // height of the circle. The result is used to draw a scan line and
+ // its mirror image below it.
+ // The following formula has been simplified from our original. We
+ // are using half of the width of the circle because we are provided
+ // with a center and we need left/right coordinates.
+ double dx = floor(sqrt((2.0 * r * dy) - (dy * dy)));
+ int x = cx - dx;
+ // Grab a pointer to the left-most pixel for each half of the circle
+ Uint8 *target_pixel_a = (Uint8 *)surface->pixels + ((int)(cy + r - dy)) * surface->pitch + x * bpp;
+ Uint8 *target_pixel_b = (Uint8 *)surface->pixels + ((int)(cy - r + dy)) * surface->pitch + x * bpp;
+
+
+
+ for (; x <= cx + dx; x++)
+ {
+ *(Uint32 *)target_pixel_a = pixel;
+ *(Uint32 *)target_pixel_b = pixel;
+ target_pixel_a += bpp;
+ target_pixel_b += bpp;
+ }
+ }
+}
+
+static void qemu_sdl_cleanup(void)
+{
+ if (sdl_cursor_normal)
+ SDL_FreeCursor(sdl_cursor_normal);
+
+ SDL_FreeSurface(qemu_mts.finger_point);
+
+ SDL_QuitSubSystem(SDL_INIT_VIDEO);
+}
+
static void qemu_sdl_init(qemu_state_t *qemu_state)
{
GtkWidget *qw = GTK_WIDGET(qemu_state);
gchar SDL_windowhack[32];
SDL_SysWMinfo info;
long window;
+ int temp;
if (use_qemu_display)
return;
exit(1);
}
+ /* cursor init */
+ sdl_cursor_normal = sdl_cursor_init(cursor_left_ptr_xpm);
+ SDL_SetCursor(sdl_cursor_normal);
+
+ /* finger point surface init */
+ qemu_mts.finger_point_size = DEFAULT_FINGER_POINT_SIZE;
+ temp = qemu_mts.finger_point_size / 2;
+ qemu_mts.finger_point = SDL_CreateRGBSurface(SDL_SRCALPHA | SDL_HWSURFACE,
+ qemu_mts.finger_point_size + 2, qemu_mts.finger_point_size + 2, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
+
+ sdl_fill_circle(qemu_mts.finger_point, temp, temp, temp, DEFAULT_FINGER_POINT_COLOR); //finger point
+ sdl_draw_circle(qemu_mts.finger_point, temp, temp, temp, 0xFF000000); // finger point outline
+
+ //atexit(qemu_sdl_cleanup); TODO:
+
qemu_state->surface_screen = SDL_SetVideoMode(qemu_state->width,
qemu_state->height, 0, qemu_state->flags);
static void qemu_update (qemu_state_t *qemu_state)
{
+ int i = 0;
+ SDL_Rect r;
SDL_Surface *surface = NULL;
if (!qemu_state->ds)
surface = SDL_GetVideoSurface ();
- if ((qemu_state->scale == 1) && (UISTATE.current_mode %4 == 0))
- SDL_BlitSurface(qemu_state->surface_qemu, NULL, qemu_state->surface_screen, NULL);
- else
- {
+ if (qemu_state->scale == 1) {
+ if (UISTATE.current_mode %4 != 0) { //rotation
+ // work-around to remove afterimage on black color in Window and Ubuntu 11.10
+ if( qemu_state->surface_qemu ) {
+ // set color key 'magenta'
+ qemu_state->surface_qemu->format->colorkey = 0xFF00FF;
+ }
+
+ SDL_Surface *rot_screen;
+ rot_screen = rotozoomSurface(qemu_state->surface_qemu,
+ (UISTATE.current_mode %4) * 90, 1, SMOOTHING_ON);
+ SDL_BlitSurface(rot_screen, NULL, qemu_state->surface_screen, NULL);
+
+ SDL_FreeSurface(rot_screen);
+ } else {
+ SDL_BlitSurface(qemu_state->surface_qemu, NULL, qemu_state->surface_screen, NULL);
+ }
+
+ /* draw finger points (multi-touch) */
+ for (i = 0; i < qemu_mts.finger_cnt; i++) {
+ r.x = qemu_mts.finger_slot[i].x - (qemu_mts.finger_point_size / 2);
+ r.y = qemu_mts.finger_slot[i].y - (qemu_mts.finger_point_size / 2);
+ r.w = r.h = qemu_mts.finger_point_size;
+
+ SDL_BlitSurface(qemu_mts.finger_point, NULL, qemu_state->surface_screen, &r);
+ }
+ } else { //resize
// work-around to remove afterimage on black color in Window and Ubuntu 11.10
if( qemu_state->surface_qemu ) {
// set color key 'magenta'
down_screen = rotozoomSurface(qemu_state->surface_qemu,
(UISTATE.current_mode %4) * 90, 1 / qemu_state->scale, SMOOTHING_ON);
SDL_BlitSurface(down_screen, NULL, qemu_state->surface_screen, NULL);
+
+ /* draw finger points (multi-touch) */
+ for (i = 0; i < qemu_mts.finger_cnt; i++) {
+ r.x = (qemu_mts.finger_slot[i].x - qemu_mts.finger_point_size) / qemu_state->scale;
+ r.y = (qemu_mts.finger_slot[i].y - qemu_mts.finger_point_size) / qemu_state->scale;
+ r.w = r.h = qemu_mts.finger_point_size;
+
+ SDL_BlitSurface(qemu_mts.finger_point, NULL, qemu_state->surface_screen, &r);
+ }
+
SDL_FreeSurface(down_screen);
}
gint qemu_widget_new (GtkWidget **widget);
gint qemu_widget_expose (GtkWidget *widget, GdkEventExpose *event);
+
+#define MAX_MULTI_TOUCH_CNT 2
+#define DEFAULT_FINGER_POINT_SIZE 32
+#define DEFAULT_FINGER_POINT_COLOR 0x7E0f0f0f
+
+typedef struct _finger_point {
+ int x; int y;
+ int dx; int dy;
+} finger_point;
+
+typedef struct _multi_touch_state {
+ int multitouch_enable;
+ int finger_cnt;
+ finger_point finger_slot[MAX_MULTI_TOUCH_CNT];
+ int finger_point_size;
+ SDL_Surface* finger_point;
+} multi_touch_state;
+
#endif