/* * Instead of polling the X connection socket we leave this to * xcb_poll_for_event() which knows better than we can ever know. * */ static void xcb_check_cb(EV_P_ ev_check *w, int revents) { xcb_generic_event_t *event; while ((event = xcb_poll_for_event(conn)) != NULL) { if (event->response_type == 0) { xcb_generic_error_t *error = (xcb_generic_error_t*)event; if (debug_mode) fprintf(stderr, "X11 Error received! sequence 0x%x, error_code = %d\n", error->sequence, error->error_code); free(event); continue; } /* Strip off the highest bit (set if the event is generated) */ int type = (event->response_type & 0x7F); switch (type) { case XCB_KEY_PRESS: handle_key_press((xcb_key_press_event_t*)event); break; case XCB_KEY_RELEASE: handle_key_release((xcb_key_release_event_t*)event); /* If this was the backspace or escape key we are back at an * empty input, so turn off the screen if DPMS is enabled */ if (dpms && input_position == 0) dpms_turn_off_screen(conn); break; case XCB_VISIBILITY_NOTIFY: handle_visibility_notify((xcb_visibility_notify_event_t*)event); break; case XCB_MAP_NOTIFY: if (!dont_fork) { /* After the first MapNotify, we never fork again. We don’t * expect to get another MapNotify, but better be sure… */ dont_fork = true; /* In the parent process, we exit */ if (fork() != 0) exit(0); ev_loop_fork(EV_DEFAULT); } break; case XCB_MAPPING_NOTIFY: handle_mapping_notify((xcb_mapping_notify_event_t*)event); break; case XCB_CONFIGURE_NOTIFY: handle_screen_resize(); break; } free(event); } }
/* process_character: [fdwatch thread] * This is where most of the work gets done. CH is a byte read in * from the keyboard's fd. This function finds the Allegro equivalent * of that key code, figures out which ASCII character that key * generates (if any), and then calls the handle_key_press() and * handle_key_release() functions with that information. It also does * some things with modifier keys. */ static void process_character(unsigned char ch) { /* read kernel's keycode and convert to Allegro's keycode */ int keycode = ch & 0x7f; bool press = !(ch & 0x80); int mycode = kernel_to_mycode[keycode]; /* if the key was something weird we don't understand, skip it */ if (mycode == 0) return; /* process modifiers */ if (mycode >= ALLEGRO_KEY_MODIFIERS) { int flag = modifier_table[mycode - ALLEGRO_KEY_MODIFIERS]; if (press) { if (flag & KB_MODIFIERS) the_keyboard.modifiers |= flag; else if ((flag & KB_LED_FLAGS) && the_keyboard.key_led_flag) the_keyboard.modifiers ^= flag; } else { /* XXX: if the user presses LCTRL, then RCTRL, then releases * LCTRL, the ALLEGRO_KEYMOD_CTRL modifier should still be on. */ if (flag & KB_MODIFIERS) the_keyboard.modifiers &= ~flag; } } /* call the handlers */ if (press) { int ascii = keycode_to_char(keycode); /* switch VT if the user requested so */ if (ascii < 0) { int console = -ascii; int last_console; ioctl(the_keyboard.fd, VT_OPENQRY, &last_console); if (console < last_console) if (ioctl(the_keyboard.fd, VT_ACTIVATE, console) == 0) return; } handle_key_press(mycode, ascii); } else { handle_key_release(mycode); } /* three-finger salute for killing the program */ if ((the_keyboard.three_finger_flag) && ((mycode == ALLEGRO_KEY_DELETE) || (mycode == ALLEGRO_KEY_END)) && (the_keyboard.modifiers & ALLEGRO_KEYMOD_CTRL) && (the_keyboard.modifiers & ALLEGRO_KEYMOD_ALT)) { kill(main_pid, SIGTERM); } }
/* key_dinput_handle_scancode: [input thread] * Handles a single scancode. */ static void key_dinput_handle_scancode(unsigned char scancode, int pressed) { HWND allegro_wnd = win_get_window(); static int ignore_three_finger_flag = FALSE; /* ignore special Windows keys (alt+tab, alt+space, (ctrl|alt)+esc) */ if (((scancode == DIK_TAB) && (_key_shifts & KB_ALT_FLAG)) || ((scancode == DIK_SPACE) && (_key_shifts & KB_ALT_FLAG)) || ((scancode == DIK_ESCAPE) && (_key_shifts & (KB_CTRL_FLAG | KB_ALT_FLAG)))) return; /* alt+F4 triggers a WM_CLOSE under Windows */ if ((scancode == DIK_F4) && (_key_shifts & KB_ALT_FLAG)) { if (pressed) PostMessage(allegro_wnd, WM_CLOSE, 0, 0); return; } /* Special case KEY_PAUSE as flip-flop key. */ if (scancode == DIK_PAUSE) { if (!pressed) return; if (key[KEY_PAUSE]) pressed = 0; else pressed = 1; } /* if not foreground, filter out press codes and handle only release codes */ if (!wnd_sysmenu || !pressed) { /* three-finger salute for killing the program */ if (three_finger_flag && (_key_shifts & KB_CTRL_FLAG) && (_key_shifts & KB_ALT_FLAG)) { if (scancode == 0x00) { /* when pressing CTRL-ALT-DEL, Windows launches CTRL-ALT-EVERYTHING */ ignore_three_finger_flag = TRUE; } else if (!ignore_three_finger_flag && (scancode == DIK_END || scancode == DIK_NUMPAD1)) { /* we can now safely assume the user hit CTRL-ALT-END as opposed to CTRL-ALT-DEL */ _TRACE(PREFIX_I "Terminating application\n"); abort(); } else if (ignore_three_finger_flag && scancode == 0xff) { /* Windows is finished with CTRL-ALT-EVERYTHING - lets return to normality */ ignore_three_finger_flag = FALSE; _key_shifts = 0; } } if (pressed) handle_key_press(scancode); else handle_key_release(scancode); } }
int wikilib_run(void) { int sleep; long time_now; struct wl_input_event ev; int more_events = 0; unsigned long last_event_time = 0; int rc; /* * test searching code... */ article_buf_pointer = NULL; search_init(); history_list_init(); malloc_status_simple(); print_intro(); #ifndef INCLUDED_FROM_KERNEL if (!load_init_article(idx_init_article)) { display_mode = DISPLAY_MODE_ARTICLE; last_display_mode = DISPLAY_MODE_INDEX; } #endif render_string(SUBTITLE_FONT_IDX, -1, 55, MESSAGE_TYPE_A_WORD, strlen(MESSAGE_TYPE_A_WORD), 0); for (;;) { if (more_events) sleep = 0; else sleep = 1; if (!more_events && display_mode == DISPLAY_MODE_ARTICLE && render_article_with_pcf()) sleep = 0; else if (!more_events && display_mode == DISPLAY_MODE_INDEX && render_search_result_with_pcf()) sleep = 0; else if (!more_events && display_mode == DISPLAY_MODE_HISTORY && render_history_with_pcf()) sleep = 0; if (finger_move_speed != 0) { scroll_article(); sleep = 0; } #ifdef INCLUDED_FROM_KERNEL time_now = get_time_ticks(); if(display_mode == DISPLAY_MODE_INDEX) { if (press_delete_button && get_search_string_len()>0) { sleep = 0; if(time_diff(time_now, start_search_time) > seconds_to_ticks(3.5)) { if (!clear_search_string()) { search_string_changed_remove = true; search_reload_ex(SEARCH_RELOAD_NORMAL); } press_delete_button = false; } else if (time_diff(time_now, start_search_time) > seconds_to_ticks(0.5) && time_diff(time_now, last_delete_time) > seconds_to_ticks(0.25)) { if (!search_remove_char(0)) { search_string_changed_remove = true; search_reload_ex(SEARCH_RELOAD_NO_POPULATE); } last_delete_time = time_now; } } } else if (display_mode == DISPLAY_MODE_RESTRICTED) { if (press_delete_button && get_password_string_len()>0) { sleep = 0; time_now = get_time_ticks(); if(time_diff(time_now, start_search_time) > seconds_to_ticks(3.5)) { clear_password_string(); press_delete_button = false; } else if (time_diff(time_now, start_search_time) > seconds_to_ticks(0.5) && time_diff(time_now, last_delete_time) > seconds_to_ticks(0.25)) { password_remove_char(); last_delete_time = time_now; } } } #endif if (!more_events && display_mode == DISPLAY_MODE_INDEX && fetch_search_result(0, 0, 0)) { sleep = 0; } if (keyboard_key_reset_invert(KEYBOARD_RESET_INVERT_CHECK)) // check if need to reset invert sleep = 0; if (check_invert_link()) // check if need to invert link sleep = 0; if (sleep) { if (time_diff(get_time_ticks(), last_event_time) > seconds_to_ticks(15)) rc = history_list_save(HISTORY_SAVE_POWER_OFF); else rc = history_list_save(HISTORY_SAVE_NORMAL); if (rc > 0) { #ifdef INCLUDED_FROM_KERNEL delay_us(200000); // for some reason, save may not work if no delay #endif } else if (rc < 0) sleep = 0; // waiting for last_event_time timeout to save the history } wl_input_wait(&ev, sleep); more_events = 1; switch (ev.type) { case WL_INPUT_EV_TYPE_CURSOR: handle_cursor(&ev); last_event_time = get_time_ticks(); break; case WL_INPUT_EV_TYPE_KEYBOARD: if (ev.key_event.value != 0) { b_show_scroll_bar = 0; handle_key_release(ev.key_event.keycode); } last_event_time = get_time_ticks(); break; case WL_INPUT_EV_TYPE_TOUCH: handle_touch(&ev); last_event_time = ev.touch_event.ticks; break; default: more_events = 0; break; } } /* never reached */ return 0; }
/* _al_xwin_keyboard_handler: * Keyboard "interrupt" handler. */ void _al_xwin_keyboard_handler(XKeyEvent *event, ALLEGRO_DISPLAY *display) { int keycode; if (!xkeyboard_installed) return; keycode = keycode_to_scancode[event->keycode]; if (keycode == -1) keycode = find_unknown_key_assignment(event->keycode); update_shifts(event); /* Special case the pause key. */ if (keycode == ALLEGRO_KEY_PAUSE) { /* Allegro ignore's releasing of the pause key. */ if (event->type == KeyRelease) return; if (pause_key) { event->type = KeyRelease; pause_key = 0; } else { pause_key = 1; } } if (event->type == KeyPress) { /* Key pressed. */ int len; char buffer[16]; int unicode = 0; int filtered = 0; #if defined (ALLEGRO_XWINDOWS_WITH_XIM) && defined(X_HAVE_UTF8_STRING) if (xic) { len = Xutf8LookupString(xic, event, buffer, sizeof buffer, NULL, NULL); } else #endif { /* XLookupString is supposed to only use ASCII. */ len = XLookupString(event, buffer, sizeof buffer, NULL, NULL); } buffer[len] = '\0'; ALLEGRO_USTR_INFO info; const ALLEGRO_USTR *ustr = al_ref_cstr(&info, buffer); unicode = al_ustr_get(ustr, 0); if (unicode < 0) unicode = 0; #ifdef ALLEGRO_XWINDOWS_WITH_XIM ALLEGRO_DISPLAY_XGLX *glx = (void *)display; filtered = XFilterEvent((XEvent *)event, glx->window); #endif if (keycode || unicode) { handle_key_press(keycode, unicode, filtered, _key_shifts, display); } } else { /* Key release. */ /* HACK: * Detect key repeat by looking forward to see if this release is * followed by a press event, in which case we assume that this release * event was generated in response to that key press event. Events are * simultaneous if they are separated by less than 4 ms (a value that * worked well on one machine where this hack was needed). * * This is unnecessary on systems where XkbSetDetectableAutorepeat works. */ if (XPending(event->display) > 0) { ALLEGRO_KEY_REPEAT_DATA d; XEvent dummy; d.event = event; d.found = false; XCheckIfEvent(event->display, &dummy, check_for_repeat, (XPointer)&d); if (d.found) { return; } } handle_key_release(keycode, display); } }
int main(int argc, char *argv[]) { format = sstrdup("%s"); char *socket_path = NULL; char *pattern = sstrdup("pango:monospace 8"); int o, option_index = 0; static struct option long_options[] = { {"socket", required_argument, 0, 's'}, {"version", no_argument, 0, 'v'}, {"limit", required_argument, 0, 'l'}, {"prompt", required_argument, 0, 'P'}, {"prefix", required_argument, 0, 'p'}, {"format", required_argument, 0, 'F'}, {"font", required_argument, 0, 'f'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}}; char *options_string = "s:p:P:f:l:F:vh"; while ((o = getopt_long(argc, argv, options_string, long_options, &option_index)) != -1) { switch (o) { case 's': FREE(socket_path); socket_path = sstrdup(optarg); break; case 'v': printf("i3-input " I3_VERSION); return 0; case 'p': /* This option is deprecated, but will still work in i3 v4.1, 4.2 and 4.3 */ fprintf(stderr, "i3-input: WARNING: the -p option is DEPRECATED in favor of the -F (format) option\n"); FREE(format); sasprintf(&format, "%s%%s", optarg); break; case 'l': limit = atoi(optarg); break; case 'P': i3string_free(prompt); prompt = i3string_from_utf8(optarg); break; case 'f': FREE(pattern); pattern = sstrdup(optarg); break; case 'F': FREE(format); format = sstrdup(optarg); break; case 'h': printf("i3-input " I3_VERSION "\n"); printf("i3-input [-s <socket>] [-F <format>] [-l <limit>] [-P <prompt>] [-f <font>] [-v]\n"); printf("\n"); printf("Example:\n"); printf(" i3-input -F 'workspace \"%%s\"' -P 'Switch to workspace: '\n"); return 0; } } printf("using format \"%s\"\n", format); int screen; conn = xcb_connect(NULL, &screen); if (!conn || xcb_connection_has_error(conn)) die("Cannot open display\n"); sockfd = ipc_connect(socket_path); root_screen = xcb_aux_get_screen(conn, screen); root = root_screen->root; symbols = xcb_key_symbols_alloc(conn); init_dpi(); font = load_font(pattern, true); set_font(&font); if (prompt != NULL) prompt_offset = predict_text_width(prompt); const xcb_rectangle_t win_pos = get_window_position(); /* Open an input window */ win = xcb_generate_id(conn); xcb_create_window( conn, XCB_COPY_FROM_PARENT, win, /* the window id */ root, /* parent == root */ win_pos.x, win_pos.y, win_pos.width, win_pos.height, /* dimensions */ 0, /* X11 border = 0, we draw our own */ XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_WINDOW_CLASS_COPY_FROM_PARENT, /* copy visual from parent */ XCB_CW_BACK_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK, (uint32_t[]){ 0, /* back pixel: black */ 1, /* override redirect: don’t manage this window */ XCB_EVENT_MASK_EXPOSURE}); /* Map the window (make it visible) */ xcb_map_window(conn, win); /* Initialize the drawable surface */ draw_util_surface_init(conn, &surface, win, get_visualtype(root_screen), win_pos.width, win_pos.height); /* Grab the keyboard to get all input */ xcb_flush(conn); /* Try (repeatedly, if necessary) to grab the keyboard. We might not * get the keyboard at the first attempt because of the keybinding * still being active when started via a wm’s keybinding. */ xcb_grab_keyboard_cookie_t cookie; xcb_grab_keyboard_reply_t *reply = NULL; int count = 0; while ((reply == NULL || reply->status != XCB_GRAB_STATUS_SUCCESS) && (count++ < 500)) { cookie = xcb_grab_keyboard(conn, false, win, XCB_CURRENT_TIME, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); reply = xcb_grab_keyboard_reply(conn, cookie, NULL); usleep(1000); } if (reply->status != XCB_GRAB_STATUS_SUCCESS) { fprintf(stderr, "Could not grab keyboard, status = %d\n", reply->status); exit(-1); } xcb_flush(conn); xcb_generic_event_t *event; while ((event = xcb_wait_for_event(conn)) != NULL) { if (event->response_type == 0) { fprintf(stderr, "X11 Error received! sequence %x\n", event->sequence); continue; } /* Strip off the highest bit (set if the event is generated) */ int type = (event->response_type & 0x7F); switch (type) { case XCB_KEY_PRESS: handle_key_press(NULL, conn, (xcb_key_press_event_t *)event); break; case XCB_KEY_RELEASE: handle_key_release(NULL, conn, (xcb_key_release_event_t *)event); break; case XCB_EXPOSE: if (((xcb_expose_event_t *)event)->count == 0) { handle_expose(NULL, conn, (xcb_expose_event_t *)event); } break; } free(event); } draw_util_surface_free(conn, &surface); return 0; }