1/* fakekey.c 2 * Functions for simulating keypresses. 3 * 4 * Copyright (C) 2010 the Speakup Team 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 */ 20#include <linux/types.h> 21#include <linux/slab.h> 22#include <linux/preempt.h> 23#include <linux/percpu.h> 24#include <linux/input.h> 25 26#include "speakup.h" 27 28#define PRESSED 1 29#define RELEASED 0 30 31static DEFINE_PER_CPU(bool, reporting_keystroke); 32 33static struct input_dev *virt_keyboard; 34 35int speakup_add_virtual_keyboard(void) 36{ 37 int err; 38 39 virt_keyboard = input_allocate_device(); 40 41 if (!virt_keyboard) 42 return -ENOMEM; 43 44 virt_keyboard->name = "Speakup"; 45 virt_keyboard->id.bustype = BUS_VIRTUAL; 46 virt_keyboard->phys = "speakup/input0"; 47 virt_keyboard->dev.parent = NULL; 48 49 __set_bit(EV_KEY, virt_keyboard->evbit); 50 __set_bit(KEY_DOWN, virt_keyboard->keybit); 51 52 err = input_register_device(virt_keyboard); 53 if (err) { 54 input_free_device(virt_keyboard); 55 virt_keyboard = NULL; 56 } 57 58 return err; 59} 60 61void speakup_remove_virtual_keyboard(void) 62{ 63 if (virt_keyboard != NULL) { 64 input_unregister_device(virt_keyboard); 65 virt_keyboard = NULL; 66 } 67} 68 69/* 70 * Send a simulated down-arrow to the application. 71 */ 72void speakup_fake_down_arrow(void) 73{ 74 unsigned long flags; 75 76 /* disable keyboard interrupts */ 77 local_irq_save(flags); 78 /* don't change CPU */ 79 preempt_disable(); 80 81 __this_cpu_write(reporting_keystroke, true); 82 input_report_key(virt_keyboard, KEY_DOWN, PRESSED); 83 input_report_key(virt_keyboard, KEY_DOWN, RELEASED); 84 __this_cpu_write(reporting_keystroke, false); 85 86 /* reenable preemption */ 87 preempt_enable(); 88 /* reenable keyboard interrupts */ 89 local_irq_restore(flags); 90} 91 92/* 93 * Are we handling a simulated keypress on the current CPU? 94 * Returns a boolean. 95 */ 96bool speakup_fake_key_pressed(void) 97{ 98 return this_cpu_read(reporting_keystroke); 99} 100